Rust: Coleções comuns do Rust

Última atualização: 2026-08-26

VecDeque é uma fila de duas extremidades que permite inserções e exclusões eficientes em ambas as extremidades; BTreeMap é um mapa ordenado de chave-valor que permite consultas por intervalo. São membros “especializados” da biblioteca de coleções do Rust.

Se um Vec é como “esperar na fila para entrar no ônibus” (só é possível entrar no final da fila), então um VecDeque é como “alguém furando a fila” (é possível entrar e sair por qualquer uma das extremidades). Se um HashMap é como um “dicionário” (consultas aleatórias), então um BTreeMap é como uma “lista de contatos” (organizada em ordem alfabética, e você pode ir direto para uma página específica para começar a ler).


1. O que você vai aprender


2. Diagramas conceituais

O diagrama comparativo do Mermaid a seguir ilustra as diferenças entre a fila de duas extremidades VecDeque e a estrutura de dados BTreeMap (mapa em árvore B):

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. A história de um sistema de filas e senhas

(1) Problema: Simulação de uma fila usando o Vec, mas tanto furar a fila quanto sair dela são lentos

Tom (Tom) está desenvolvendo um sistema de gerenciamento de filas para restaurantes. Os clientes pegam um número ao chegarem, e o garçom chama o número para que eles se sentem à mesa.

No início, ele implementou isso usando o 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);

A operação de Vec remove(0) tem complexidade O(n) — após remover o primeiro elemento, todos os elementos restantes precisam ser deslocados uma posição para a frente. Se houver 10.000 pessoas na fila, cada vez que um número for chamado, 9.999 elementos precisam ser deslocados. Isso claramente não é adequado para um sistema de produção.

(2) Requisitos mais complexos: prioridade VIP + busca por número

Para piorar a situação, o gerente do restaurante disse:

O Vec simplesmente não consegue lidar com esses requisitos de jeito nenhum.

(3) Soluções para coleções em Rust

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
}

As operações em ambas as extremidades de um VecDeque têm complexidade O(1), enquanto um BTreeMap classifica automaticamente as chaves e suporta consultas por intervalo. O primeiro resolve o problema do “fila”, e o segundo resolve o problema da “busca ordenada”.


4. Conceitos fundamentais

(1) Comparação entre quatro estruturas de conjuntos

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) Comparação do desempenho de quatro tipos de conjuntos

Operação Vec VecDeque HashMap BTreeMap
Inserção na cauda O(1) amortizado O(1) O(1) amortizado O(log n)
Inserção no início O(n) O(1)
Acesso por índice O(1) O(1)
Pesquisa de chave O(1) amortizado O(log n)
Consulta de intervalo Não suportado Não suportado Não suportado O(log n + k)
Traversal ordenada Deve estar ordenada Deve estar ordenada Não ordenada O(n) (ordenada)
Uso de memória Baixo Baixo Médio Médio

(3) Estratégia de seleção

Cenário Coleção recomendada Motivo
Fila / Buffer (operações em ambas as extremidades) VecDeque O(1) em ambas as extremidades — nada é mais adequado do que isso
Requer percorrimento ordenado por chave BTreeMap Ordenado automaticamente; não são necessárias etapas adicionais de ordenação
Consultas por intervalo necessárias BTreeMap A única coleção que suporta consultas por intervalo
Requer apenas operações na cauda Vec Mais simples e com menor consumo de memória
Requer apenas consultas de chave-valor HashMap Consultas em O(1), mais rápidas que o BTreeMap
Inserção e exclusão frequentes de elementos no meio LinkedList Teoricamente O(1), mas raramente usada na prática

(4) Referência rápida aos métodos comuns do VecDeque e do BTreeMap

Conjunto Método Descrição Complexidade temporal
VecDeque push_front(val) Inserção no início O(1)
VecDeque push_back(val) Inserir no final O(1)
VecDeque pop_front() Retirar o primeiro elemento da matriz O(1)
VecDeque pop_back() Retirar do final O(1)
VecDeque front() / back() Exibir o primeiro e o último elementos O(1)
VecDeque len() / is_empty() Consulta de comprimento O(1)
BTreeMap insert(k, v) Inserir par chave-valor O(log n)
BTreeMap get(&k) Pesquisa por chave O(log n)
BTreeMap remove(&k) Exclusão por chave O(log n)
BTreeMap range(start..=end) Consulta de intervalo O(log n + k)
BTreeMap first_key_value() Menor número de pares chave-valor O(log n)
BTreeMap last_key_value() Número máximo de pares chave-valor O(log n)

5. Dar o exemplo

▶ Exemplo 1: Fila de duas extremidades com VecDeque — Sistema de fila e emissão de senhas (Dificuldade ⭐)

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);
    }
}

Resultado:

TEXT 📖 Somente leitura
Current number of people in line: 5
At the head of the line: Some("VIP-Eve"), Bringing up the rear: Some("Charlie")

Call Order:
  VIP-Eve Take a seat
  VIP-David Take a seat
  Alice Take a seat
  Bob Take a seat
  Charlie Take a seat

push_front() e push_back() são ambas operações de complexidade O(1). front() e back() retornam referências à frente e ao fim da fila, respectivamente, sem remover os elementos. pop_front() remove e retorna o elemento que está na frente da fila.


▶ Exemplo 2: BTreeMap — Armazenamento ordenado de chave-valor: Classificações por nota (Dificuldade ⭐⭐)

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());
}

Resultado:

TEXT 📖 Somente leitura
=== 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))

O BTreeMap ordena automaticamente as chaves na ordem Ord. A ordem de classificação padrão para strings é lexicográfica; portanto, “Alice” vem primeiro e “David” vem por último. first_key_value() e last_key_value() proporcionam acesso eficiente ao primeiro e ao último elemento.


▶ Exemplo 3: Consulta de intervalo no BTreeMap — Consulta de intervalo de datas (Dificuldade ⭐⭐)

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);
}

Resultado:

TEXT 📖 Somente leitura
=== 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() é um método exclusivo do BTreeMap. Ele aceita uma expressão de intervalo (.. para um intervalo aberto, ..= para um intervalo fechado e start.. para um intervalo semiaberto) e retorna um iterador. Isso é algo que o HashMap não consegue fazer.


▶ Exemplo 4: Comparação de desempenho entre quatro tipos de conjuntos (Dificuldade ⭐⭐⭐)

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());
}

Resultado (exemplo; o tempo real pode variar dependendo da máquina):

TEXT 📖 Somente leitura
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

Os dados de desempenho mostram que o HashMap é o mais rápido para consultas (O(1)), seguido pelo BTreeMap (O(log n)), enquanto o Vec é o mais lento para consultas lineares (O(n)). Para inserções, a inserção na cauda é mais rápida com o Vec e o VecDeque, e mais lenta com o BTreeMap. Isso confirma que “não existe uma solução milagrosa” — a escolha da coleção depende do caso de uso específico.


▶ Exemplo 5: Exercício abrangente — Sistema de agendamento de tarefas (Dificuldade ⭐⭐⭐)

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);
}

Resultado:

TEXT 📖 Somente leitura
=== 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 um VecDeque como fila FIFO (push_back + pop_front); o BTreeMap agrupa os itens por prioridade e os classifica automaticamente; range(0..=1) exibe apenas tarefas de alta prioridade; o VecDeque de capacidade fixa implementa um histórico das “últimas N entradas”.


❓ Perguntas Frequentes

P: Qual é a diferença entre VecDeque e Vec? Quando devo usar o VecDeque? R: O VecDeque suporta operações O(1) em ambas as extremidades, enquanto o Vec suporta operações O(1) apenas na cauda. Se você precisar remover elementos da cabeça (como em um cenário de fila) ou realizar inserções/exclusões em ambas as extremidades, use o VecDeque. Se você precisar apenas de operações na cauda (como em um cenário de pilha), usar o Vec é mais simples.

P: Qual é a diferença entre um BTreeMap e um HashMap? R: Um BTreeMap é ordenado, enquanto um HashMap não é ordenado. Um BTreeMap armazena entradas em ordem de chave e suporta consultas por intervalo, mas as inserções e pesquisas têm complexidade temporal de O(log n). Um HashMap não garante nenhuma ordem específica, mas as inserções e pesquisas têm complexidade temporal de O(1). Use um BTreeMap quando for necessário fazer ordenamento ou consultas por intervalo; caso contrário, um HashMap é mais rápido.

P: Por que o LinkedList é raramente usado em Rust? R: Cada nó em um LinkedList acarreta uma sobrecarga adicional de ponteiros e não é compatível com o cache. Embora as inserções e exclusões sejam, teoricamente, O(1), o desempenho real costuma ser pior do que o do Vec ou do VecDeque, pois a memória não contígua leva a baixas taxas de acertos no cache. A menos que você esteja realizando um grande número de inserções e exclusões no meio da lista e lidando com uma quantidade enorme de dados, deve priorizar o uso de Vec ou VecDeque.

P: Como o BTreeMap implementa a paginação para a operação range? R: Ele utiliza next() e nth() para implementar a paginação baseada em cursor. Por exemplo, map.range(start..).take(20) recupera os primeiros 20 registros a partir de start e usa a chave do último registro como o novo start para a próxima solicitação. Isso é mais eficiente do que LIMIT OFFSET ao lidar com grandes conjuntos de dados.

P: Existe alguma regra mnemônica simples para escolher entre os quatro tipos de coleção? R: Sim. “Use Vec para operações na extremidade, VecDeque para operações em ambas as extremidades, HashMap para consultas não ordenadas e BTreeMap para consultas ordenadas.” Se você se lembrar dessas quatro frases, não vai errar na escolha em 90% dos casos.


📖 Resumo


📝 Exercícios

  1. Dificuldade ⭐: Implemente um “histórico de desfazer” usando VecDeque. Registre cada operação usando push_back e, ao desfazer, remova a operação mais recente usando pop_back. Simule três operações seguidas de duas operações de desfazer e imprima o conteúdo de cada operação.
  2. Dificuldade ⭐⭐: Implemente um “Sistema de Gerenciamento de Notas dos Alunos” utilizando um mapa em árvore B. Insira os nomes e as notas de 5 alunos e imprima a classificação em ordem decrescente por nota (Dica: um mapa em árvore B não pode classificar diretamente por valor; você deve usar a nota como chave e o nome como valor, ou usar iter().rev()).
  3. Dificuldade ⭐⭐⭐: Escreva uma função fn analyze_collections(data: &[i32]) que receba como entrada uma fatia de inteiros, conte o número de ocorrências de cada dígito usando, respectivamente, VecDeque, HashMap e BTreeMap, e compare as diferenças de desempenho entre as três abordagens (usando std::time::Instant para medir o tempo).
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%