Rust: Common Rust Collections

Last updated: 2026-08-26

VecDeque is a double-ended queue that supports efficient insertion and deletion at both ends; BTreeMap is an ordered key-value map that supports range queries. They are "specialized" members of Rust's collection library.

If a Vec is like “waiting in line to get on a bus” (you can only join at the end of the line), then a VecDeque is like “someone cutting in line” (you can enter and exit from either end). If a HashMap is like a “dictionary” (random lookups), then a BTreeMap is like a “contact list” (arranged in alphabetical order, and you can flip to a specific page to start reading).


1. What You'll Learn



2. Conceptual Diagrams

The following Mermaid comparison diagram illustrates the differences between the VecDeque double-ended queue and the BTreeMap B-tree map data structures:

100%
graph LR
    subgraph VecDeque["VecDeque Double-ended queue"]
        direction LR
        V1["pop_front O(1)"] --> V2["Element1"]
        V2 --> V3["Element2"]
        V3 --> V4["..."]
        V4 --> V5["ElementN"]
        V5 --> V6["push_back O(1)"]
        V7["push_front O(1)"] -.-> V2
    end

    subgraph BTreeMap["BTreeMap BOrdered Map of Trees"]
        direction TB
        B0["Root Node"] --> B1["Left Branch<br/>Keys: A-M"]
        B0 --> B2["Right Branch<br/>Keys: N-Z"]
        B1 --> B3["(Alice, 95)"]
        B1 --> B4["(Bob, 72)"]
        B2 --> B5["(Charlie, 87)"]
        B2 --> B6["(David, 91)"]
    end

    VecDeque -.-> |Comparison of Data Structures| BTreeMap


3. The Story of a Queueing and Ticket System

(1) Problem: Simulating a queue using Vec, but both cutting in line and leaving the queue are slow

Tom (Tom) is developing a queue management system for restaurants. Customers pick up a number when they arrive, and the server calls out the number to seat them.

At first, he implemented it using Vec:

RUST
let mut queue = Vec::new();
queue.push("Customer A");   // A Get a ticket,At the back of the line
queue.push("Customer B");   // B Get a ticket,At the back of the line
queue.push("Customer C");   // C Get a ticket,At the back of the line

// Take a seat when your number is called:Remove from the front of the line
let first = queue.remove(0);  // O(n) —— All elements that follow must be moved forward!
println!("{} Take a seat", first);

Vec's remove(0) is an O(n) operation—after removing the first element, all remaining elements must be shifted forward by one position. If there are 10,000 people in line, each time a number is called, 9,999 elements must be shifted. This is clearly not suitable for a production system.

(2) More complex requirements: VIP priority + search by number

To make matters worse, the restaurant manager said:

Vec just can't handle these requirements at all.

(3) Solutions for Rust Collections

RUST
use std::collections::VecDeque;
use std::collections::BTreeMap;

fn main() {
    // VecDeque:Accessible from both the front and the back
    let mut queue = VecDeque::new();
    queue.push_back("Customer A");   // Enter at the back of the line
    queue.push_back("Customer B");
    queue.push_front("VIP");         // VIP Cutting in line at the front of the line!

    println!("Next, please take a seat.: {}", queue.pop_front().unwrap());  // VIP
    println!("Next: {}", queue.pop_front().unwrap());    // Customer A

    // BTreeMap:Ordered Key-Value Store
    let mut customers = BTreeMap::new();
    customers.insert(1001, "Alice");
    customers.insert(1003, "Bob");
    customers.insert(1002, "Charlie");

    // Automatically Sort and Output Buttons
    for (id, name) in &customers {
        println!("Get a ticket #{}: {}", id, name);
    }
    // Output: #1001: Alice, #1002: Charlie, #1003: Bob
}

Operations at both ends of a VecDeque are O(1), while a BTreeMap automatically sorts keys and supports range queries. The former solves the "queuing" problem, and the latter solves the "ordered search" problem.



4. Core Concepts

(1) Comparison of Four Set Structures

100%
graph TB
    A[Rust Collection Library] --> B[Vec: Contiguous Arrays]
    A --> C[VecDeque: Double-ended queue]
    A --> D[HashMap: Hash Table]
    A --> E[BTreeMap: B Ordered Map of Trees]

    B --> F["push / pop: O(1) Amortized"]
    B --> G["insert(0) / remove(0): O(n)"]

    C --> H["push_front / pop_front: O(1)"]
    C --> I["push_back / pop_back: O(1)"]

    D --> J["Insert / Search: O(1) Amortized"]
    D --> K["Disorder —— No order guarantee"]

    E --> L["Insert / Search: O(log n)"]
    E --> M["Orderly —— Support for Range Queries range"]

(2) Comparison of the Performance of Four Types of Sets

Operation Vec VecDeque HashMap BTreeMap
Tail insertion O(1) amortized O(1) O(1) amortized O(log n)
Insertion at the front O(n) O(1)
Access by index O(1) O(1)
Key lookup O(1) amortized O(log n)
Range Query Not supported Not supported Not supported O(log n + k)
Ordered traversal Must be sorted Must be sorted Unordered O(n) (sorted)
Memory usage Low Low Medium Medium

(3) Selection Strategy

Scenario Recommended Collection Reason
Queue / Buffer (operations on both ends) VecDeque O(1) on both ends—nothing is more suitable than this
Requires key-sorted traversal BTreeMap Automatically sorted; no additional sorting steps required
Range Queries Required BTreeMap The only collection that supports range queries
Only requires tail operations Vec Simpler and more memory-efficient
Requires only key-value lookups HashMap O(1) lookups, faster than BTreeMap
Frequent insertion and deletion of middle elements LinkedList Theoretical O(1), but rarely used in practice

(4) Quick Reference for Common Methods of VecDeque and BTreeMap

Set Method Description Time Complexity
VecDeque push_front(val) Insert at the front O(1)
VecDeque push_back(val) Insert at the end O(1)
VecDeque pop_front() Pop the first element of the array O(1)
VecDeque pop_back() Pop from the end O(1)
VecDeque front() / back() View first and last elements O(1)
VecDeque len() / is_empty() Length Query O(1)
BTreeMap insert(k, v) Insert key-value pair O(log n)
BTreeMap get(&k) Key-based search O(log n)
BTreeMap remove(&k) Delete by key O(log n)
BTreeMap range(start..=end) Range Query O(log n + k)
BTreeMap first_key_value() Least key-value pair O(log n)
BTreeMap last_key_value() Maximum key-value pair O(log n)


5. Set Examples

▶ Example 1: VecDeque Double-Ended Queue — Queueing and Ticket Issuance System (Difficulty ⭐)

Output:

TEXT 📖 Display only
Current number of people in line: <queue.len()>
At the head of the line: <queue.front()>, Bringing up the rear: <queue.back()>

Call Order:
  <customer> Take a seat
RUST
// ============================================
// VecDeque:Basic Operations on a Double-Ended Queue
// ============================================

use std::collections::VecDeque;

fn main() {
    let mut queue: VecDeque<&str> = VecDeque::new();

    // Regular customers enter from the back of the line
    queue.push_back("Alice");
    queue.push_back("Bob");
    queue.push_back("Charlie");

    // VIP A customer cut in line from the front of the line
    queue.push_front("VIP-David");
    queue.push_front("VIP-Eve");

    println!("Current number of people in line: {}", queue.len());
    println!("At the head of the line: {:?}, Bringing up the rear: {:?}", queue.front(), queue.back());

    // Take a seat when your number is called:Remove from the front of the queue
    println!("\nCall Order:");
    while let Some(customer) = queue.pop_front() {
        println!("  {} Take a seat", customer);
    }
}

Output:

TEXT 📖 Display only
=== Transcript(Sort by Name)===
  <name>: <score>

Alice the results: <scores.get("Alice").unwrap()>
Eve There are discrepancies in the scores
Eve No results yet

First: <scores.first_key_value()>
The last one: <scores.last_key_value()>





push_front() and push_back() are both O(1) operations. front() and back() return references to the front and back of the queue, respectively, without removing the elements. pop_front() removes and returns the element at the front of the queue.


▶ Example 2: BTreeMap—Ordered Key-Value Storage: Grade Rankings (Difficulty ⭐⭐)

Output:

TEXT 📖 Display only
=== Transcript(Sort by Name)===
  <name>: <score>

Alice the results: <scores.get("Alice").unwrap()>
Eve There are discrepancies in the scores
Eve No results yet

RUST
// ============================================
// BTreeMap:Automatic Button Sorting
// ============================================

use std::collections::BTreeMap;

fn main() {
    let mut scores = BTreeMap::new();

    scores.insert("Charlie", 87);
    scores.insert("Alice", 95);
    scores.insert("Bob", 72);
    scores.insert("David", 91);

    // BTreeMap Button(Alphabetical order)Automatic Sorting
    println!("=== Transcript(Sort by Name)===");
    for (name, score) in &scores {
        println!("  {}: {}", name, score);
    }

    // Search by Key
    println!("\nAlice the results: {}", scores.get("Alice").unwrap());

    // Check for the presence of
    if scores.contains_key("Eve") {
        println!("Eve There are discrepancies in the scores");
    } else {
        println!("Eve No results yet");
    }

    // Get the first and last entries
    println!("\nFirst: {:?}", scores.first_key_value());
    println!("The last one: {:?}", scores.last_key_value());
}

Output:

TEXT 📖 Display only
=== Transcript(Sort by Name)===
  Alice: 95
  Bob: 72
  Charlie: 87
  David: 91

Alice the results: 95
Eve No results yet

First: Some(("Alice", 95))
The last one: Some(("David", 91))

BTreeMap automatically sorts keys in Ord order. The default sort order for Strings is lexicographical, so "Alice" comes first and "David" comes last. first_key_value() and last_key_value() provide efficient access to the first and last elements.


▶ Example 3: BTreeMap Range Query—Date Range Query (Difficulty ⭐⭐)

Output:

TEXT 📖 Display only
=== July 3 ~ July 7 Orders ===
  <date>: $<amount>

=== July 5 and After Orders ===
  <date>: $<amount>

RUST
// ============================================
// BTreeMap Range Query:range Methods
// ============================================

use std::collections::BTreeMap;

fn main() {
    // Simulated Order System:Date -> Order Amount
    let mut orders = BTreeMap::new();

    orders.insert("2026-07-01", 120);
    orders.insert("2026-07-03", 85);
    orders.insert("2026-07-05", 200);
    orders.insert("2026-07-07", 150);
    orders.insert("2026-07-10", 95);

    // Search orders placed between July 3 and July 7 (inclusive)
    println!("=== July 3 ~ July 7 Orders ===");
    for (date, amount) in orders.range("2026-07-03"..="2026-07-07") {
        println!("  {}: ${}", date, amount);
    }

    // Search all orders on or after July 5
    println!("\n=== July 5 and After Orders ===");
    for (date, amount) in orders.range("2026-07-05"..) {
        println!("  {}: ${}", date, amount);
    }

    // Total Amount
    let total: i32 = orders.range("2026-07-03"..="2026-07-07")
        .map(|(_, amount)| amount)
        .sum();
    println!("\nJuly 3 ~ July 7 Total Amount: ${}", total);
}

Output:

TEXT 📖 Display only
=== July 3 ~ July 7 Orders ===
  2026-07-03: $85
  2026-07-05: $200
  2026-07-07: $150

=== July 5 and After Orders ===
  2026-07-05: $200
  2026-07-07: $150
  2026-07-10: $95

July 3 ~ July 7 Total Amount: $435

range() is a method unique to BTreeMap. It accepts a Range expression (.. for an open interval, ..= for a closed interval, and start.. for a half-open interval) and returns an iterator. This is something HashMap cannot do.


▶ Example 4: Performance Comparison of Four Types of Sets (Difficulty ⭐⭐⭐)

Output:

TEXT 📖 Display only
Vec Insert at the end: <start.elapsed()>
VecDeque Insert at the end: <start.elapsed()>
HashMap Insert: <start.elapsed()>
BTreeMap Insert: <start.elapsed()>

--- Search Performance ---
Vec Linear Search: <start.elapsed()>
HashMap Search: <start.elapsed()>
BTreeMap Search: <start.elapsed()>
RUST
// ============================================
// Comparison of the Performance of Four Types of Sets:Insert 10000 element
// ============================================

use std::collections::{BTreeMap, HashMap, VecDeque};
use std::time::Instant;

fn main() {
    let n = 10_000;

    // Vec Insert at the end
    let start = Instant::now();
    let mut vec = Vec::new();
    for i in 0..n {
        vec.push(i);
    }
    println!("Vec Insert at the end: {:?}", start.elapsed());

    // VecDeque Insert at the end
    let start = Instant::now();
    let mut deque = VecDeque::new();
    for i in 0..n {
        deque.push_back(i);
    }
    println!("VecDeque Insert at the end: {:?}", start.elapsed());

    // HashMap Insert
    let start = Instant::now();
    let mut hmap = HashMap::new();
    for i in 0..n {
        hmap.insert(i, i);
    }
    println!("HashMap Insert: {:?}", start.elapsed());

    // BTreeMap Insert
    let start = Instant::now();
    let mut bmap = BTreeMap::new();
    for i in 0..n {
        bmap.insert(i, i);
    }
    println!("BTreeMap Insert: {:?}", start.elapsed());

    // Search for Performance Comparisons
    println!("\n--- Search Performance ---");

    let start = Instant::now();
    let _ = vec.contains(&9999);
    println!("Vec Linear Search: {:?}", start.elapsed());

    let start = Instant::now();
    let _ = hmap.get(&9999);
    println!("HashMap Search: {:?}", start.elapsed());

    let start = Instant::now();
    let _ = bmap.get(&9999);
    println!("BTreeMap Search: {:?}", start.elapsed());
}

Output:

TEXT 📖 Display only
Vec Insert at the end: 78.2µs
VecDeque Insert at the end: 82.1µs
HashMap Insert: 1.2ms
BTreeMap Insert: 2.8ms

--- Search Performance ---
Vec Linear Search: 42.5µs
HashMap Search: 138ns
BTreeMap Search: 312ns

The performance data shows that HashMap is the fastest for lookups (O(1)), followed by BTreeMap (O(log n)), while Vec is the slowest for linear lookups (O(n)). For insertions, tail insertion is fastest with Vec and VecDeque, and slowest with BTreeMap. This confirms that there is “no silver bullet”—the choice of collection depends on the specific use case.


▶ Example 5: Comprehensive Exercise—Task Scheduling System (Difficulty ⭐⭐⭐)

Output:

TEXT 📖 Display only
=== FIFO Queue Processing ===
[P<task.priority>] #<task.id>: <task.name>

=== Sort by priority ===
P<task_list>: <pri>

=== High-Priority Tasks (P0-P1) ===
P<task_list>: <pri>

RUST
// ============================================
// Comprehensive Example:VecDeque Queue + BTreeMap Priority
// ============================================

use std::collections::{VecDeque, BTreeMap};

#[derive(Debug, Clone)]
struct Task {
    id: u32,
    name: String,
    priority: u8,
}

fn main() {
    let mut queue: VecDeque<Task> = VecDeque::new();
    queue.push_back(Task { id: 1, name: "Check email".into(), priority: 3 });
    queue.push_back(Task { id: 2, name: "Fix bug #42".into(), priority: 1 });
    queue.push_back(Task { id: 3, name: "Write report".into(), priority: 2 });
    queue.push_back(Task { id: 4, name: "Urgent deploy".into(), priority: 0 });

    println!("=== FIFO Queue Processing ===");
    while let Some(task) = queue.pop_front() {
        println!("[P{}] #{}: {}", task.priority, task.id, task.name);
    }

    let mut priority_map: BTreeMap<u8, Vec<String>> = BTreeMap::new();
    let tasks = vec![
        ("Check email", 3u8), ("Fix bug #42", 1), ("Write report", 2),
        ("Urgent deploy", 0), ("Code review", 1), ("Team meeting", 3),
        ("Security patch", 0), ("Update docs", 2),
    ];

    for (name, pri) in tasks {
        priority_map.entry(pri).or_insert_with(Vec::new).push(name.to_string());
    }

    println!("\n=== Sort by priority ===");
    for (pri, task_list) in &priority_map {
        println!("P{}: {:?}", pri, task_list);
    }

    println!("\n=== High-Priority Tasks (P0-P1) ===");
    for (pri, task_list) in priority_map.range(0..=1) {
        println!("P{}: {:?}", pri, task_list);
    }

    let mut history: VecDeque<String> = VecDeque::with_capacity(3);
    for i in 0..5 {
        history.push_back(format!("task_{}", i));
        if history.len() > 3 {
            history.pop_front();
        }
    }
    println!("\nLast 3 history entries: {:?}", history);
}

Output:

TEXT 📖 Display only
=== FIFO Queue Processing ===
[P3] #1: Check email
[P1] #2: Fix bug #42
[P2] #3: Write report
[P0] #4: Urgent deploy

=== Sort by priority ===
P0: ["Urgent deploy", "Security patch"]
P1: ["Fix bug #42", "Code review"]
P2: ["Write report", "Update docs"]
P3: ["Check email", "Team meeting"]

=== High-Priority Tasks (P0-P1) ===
P0: ["Urgent deploy", "Security patch"]
P1: ["Fix bug #42", "Code review"]

Last 3 history entries: ["task_2", "task_3", "task_4"]

Use a VecDeque as a FIFO queue (push_back + pop_front); BTreeMap groups items by priority and automatically sorts them; range(0..=1) displays only high-priority tasks; the fixed-capacity VecDeque implements a "latest N entries" history.


❓ FAQ

Q What is the difference between VecDeque and Vec? When should I use VecDeque?
A VecDeque supports O(1) operations at both ends, while Vec only supports O(1) operations at the tail.
Q What is the difference between a BTreeMap and a HashMap?
A A BTreeMap is sorted, while a HashMap is unsorted.
Q Why is LinkedList rarely used in Rust?
A Each node in a LinkedList incurs additional pointer overhead, and it is cache-unfriendly.
Q How does BTreeMap implement pagination for the range operation?
A It uses next() and nth() to implement cursor-based pagination.
Q Is there a simple mnemonic for choosing among the four collection types?
A Yes. “Use Vec for tail operations, VecDeque for operations at both ends, HashMap for unordered lookups, and BTreeMap for ordered lookups.”

📖 Summary


📝 Exercises

  1. Difficulty ⭐: Implement an "undo history" using VecDeque. Record each operation using push_back, and when undoing, remove the most recent operation using pop_back. Simulate 3 operations followed by 2 undo operations, and print the contents of each operation.
  2. Difficulty ⭐⭐: Implement a "Student Grade Management System" using a B-Tree Map. Insert the names and grades of 5 students, and print the rankings in descending order by grade (Hint: A B-Tree Map cannot sort directly by value; you must use the grade as the key and the name as the value, or use iter().rev()).
  3. Difficulty ⭐⭐⭐: Write a function fn analyze_collections(data: &[i32]) that takes an integer slice as input, counts the number of occurrences of each digit using VecDeque, HashMap, and BTreeMap, respectively, and compares the performance differences among the three approaches (using std::time::Instant to measure the time).
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏