7.5 KiB
BTreeMap — krok za krokom
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
use std::collections::BTreeMap; // toto treba vždy
Kapitola 1: Čo to je a rozdiel oproti HashMap
BTreeMap je to isté ako HashMap — kľúč → hodnota — ale s jedným veľkým rozdielom: kľúče sú vždy zoradené.
| HashMap | BTreeMap | |
|---|---|---|
| Poradie kľúčov | náhodné | zoradené (od najmenšieho) |
| Rýchlosť | O(1) | O(log n) |
| Kedy použiť | väčšinou | keď potrebuješ zoradené kľúče |
| Import | use std::collections::HashMap |
use std::collections::BTreeMap |
use std::collections::BTreeMap;
let mut mapa = BTreeMap::new();
mapa.insert("Cyril".to_string(), 22);
mapa.insert("Anna".to_string(), 25);
mapa.insert("Boris".to_string(), 30);
// Iterácia — kľúče SÚ zoradené abecedne!
for (meno, vek) in &mapa {
println!("{}: {}", meno, vek);
}
// Anna: 25
// Boris: 30
// Cyril: 22
S HashMap by poradie bolo náhodné. S BTreeMap je vždy zoradené.
Pre čísla zoradí od najmenšieho:
let mut mapa = BTreeMap::new();
mapa.insert(3, "tri");
mapa.insert(1, "jedna");
mapa.insert(2, "dva");
for (k, v) in &mapa {
println!("{}: {}", k, v);
}
// 1: jedna
// 2: dva
// 3: tri
Úlohy 1
1a. Vytvor BTreeMap s 5 menami (String) a vekmi (u32). Vypíš ich. Over, že sú zoradené abecedne.
1b. Vytvor BTreeMap s číslami ako kľúčmi (i32 → String). Vlož ich v náhodnom poradí. Vypíš a over, že sú zoradené.
1c. Vytvor rovnakú mapu raz ako HashMap, raz ako BTreeMap. Vypíš obe. Vidíš rozdiel v poradí?
Kapitola 2: Všetko čo vieš z HashMap funguje rovnako
BTreeMap má rovnaké API ako HashMap. Všetko čo si sa naučil, funguje:
let mut mapa = BTreeMap::new();
// insert — rovnaké
mapa.insert("Anna".to_string(), 25);
let stara = mapa.insert("Anna".to_string(), 26); // Some(25)
// get — rovnaké
let vek = mapa.get("Anna"); // Some(&26)
// contains_key — rovnaké
let je_tam = mapa.contains_key("Anna"); // true
// remove — rovnaké
let odstraneny = mapa.remove("Anna"); // Some(26)
// len, is_empty — rovnaké
let pocet = mapa.len();
let prazdna = mapa.is_empty();
// entry API — rovnaké!
*mapa.entry("Boris".to_string()).or_insert(0) += 1;
mapa.entry("Cyril".to_string()).or_default();
mapa.entry("Dana".to_string())
.and_modify(|v| *v += 1)
.or_insert(1);
// get_mut — rovnaké
if let Some(vek) = mapa.get_mut("Boris") {
*vek += 10;
}
// iterácia — rovnaká syntax, ale ZORADENÉ
for (k, v) in &mapa { /* zoradené podľa kľúča */ }
for k in mapa.keys() { /* zoradené */ }
for v in mapa.values() { /* v poradí podľa zoradených kľúčov */ }
for v in mapa.values_mut() { *v += 1; }
Jediný rozdiel je, že výstup je vždy zoradený.
Úlohy 2
2a. Spočítaj výskyt každého znaku v "abrakadabra" do BTreeMap. Vypíš. V akom poradí sú znaky?
2b. Máš vektor slov. Zoskup ich podľa prvého písmena do BTreeMap<char, Vec<String>>. Over, že písmená sú zoradené.
2c. Napíš funkciu:
fn pocitaj_slova(text: &str) -> BTreeMap<String, usize>
Počet výskytov každého slova, zoradené abecedne.
Kapitola 3: Range queries — to čo HashMap nevie
Najväčšia výhoda BTreeMap: vieš sa pýtať na rozsahy kľúčov.
range — podmnožina podľa rozsahu kľúčov
let mut mapa = BTreeMap::new();
mapa.insert(1, "jedna");
mapa.insert(2, "dva");
mapa.insert(3, "tri");
mapa.insert(4, "štyri");
mapa.insert(5, "päť");
mapa.insert(6, "šesť");
mapa.insert(7, "sedem");
// Kľúče od 3 do 5 (vrátane oboch)
for (k, v) in mapa.range(3..=5) {
println!("{}: {}", k, v);
}
// 3: tri
// 4: štyri
// 5: päť
// Kľúče od 3 (bez 6)
for (k, v) in mapa.range(3..6) {
println!("{}: {}", k, v);
}
// 3: tri
// 4: štyri
// 5: päť
// Kľúče od začiatku po 3 (vrátane)
for (k, v) in mapa.range(..=3) {
println!("{}: {}", k, v);
}
// 1: jedna
// 2: dva
// 3: tri
// Kľúče od 5 do konca
for (k, v) in mapa.range(5..) {
println!("{}: {}", k, v);
}
// 5: päť
// 6: šesť
// 7: sedem
S Stringami to funguje abecedne:
let mut mapa = BTreeMap::new();
mapa.insert("Anna".to_string(), 25);
mapa.insert("Boris".to_string(), 30);
mapa.insert("Cyril".to_string(), 22);
mapa.insert("Dana".to_string(), 28);
// Mená od "B" po "D" (nezahrnie "D" lebo ..)
for (meno, vek) in mapa.range("B".to_string().."D".to_string()) {
println!("{}: {}", meno, vek);
}
// Boris: 30
// Cyril: 22
Úlohy 3
3a. Vytvor BTreeMap s kľúčmi 1 až 10 (i32 → String s názvom čísla). Vypíš len čísla 4 až 7.
3b. Máš BTreeMap študentov (meno → priemer). Vypíš len študentov, ktorých meno začína na písmená M až Z. Použi .range().
3c. Máš BTreeMap teplôt za dni v mesiaci (u32 → f64, deň → teplota). Napíš funkciu:
fn teploty_v_tyzdni(teploty: &BTreeMap<u32, f64>, od: u32, do_: u32) -> Vec<f64>
Vráti vektor teplôt pre dané dni.
Kapitola 4: first/last — prvý a posledný kľúč
BTreeMap vie efektívne nájsť najmenší a najväčší kľúč:
let mut mapa = BTreeMap::new();
mapa.insert(5, "päť");
mapa.insert(1, "jedna");
mapa.insert(9, "deväť");
mapa.insert(3, "tri");
// Prvý (najmenší) pár
let prvy = mapa.first_key_value();
// Some((&1, &"jedna"))
// Posledný (najväčší) pár
let posledny = mapa.last_key_value();
// Some((&9, &"deväť"))
// Len kľúče
let prvy_kluc = mapa.keys().next(); // Some(&1)
let posledny_kluc = mapa.keys().last(); // Some(&9)
Tieto operácie sú O(log n) — veľmi rýchle. HashMap toto nevie (musel by prejsť celú mapu).
Úlohy 4
4a. Máš BTreeMap študentov (meno → priemer). Nájdi študenta s menom prvým v abecede a posledným v abecede.
4b. Máš BTreeMap (rok: u32 → udalosť: String). Nájdi najstaršiu a najnovšiu udalosť.
Kapitola 5: Kedy HashMap, kedy BTreeMap
| Situácia | Použi |
|---|---|
| Nepotrebuješ poradie | HashMap (rýchlejší) |
| Chceš zoradený výpis | BTreeMap |
| Potrebuješ range queries | BTreeMap |
| Potrebuješ prvý/posledný | BTreeMap |
| Chceš maximálny výkon | HashMap |
Na skúške: vypis_statistiky zoradene |
BTreeMap |
Tip na skúšku: Ak zadanie hovorí "vypíš v abecednom poradí" alebo "zoradene", použi BTreeMap. Inak HashMap stačí.
Konverzia medzi nimi je jednoduchá:
use std::collections::{HashMap, BTreeMap};
// HashMap → BTreeMap
let hash: HashMap<String, i32> = /* ... */;
let btree: BTreeMap<String, i32> = hash.into_iter().collect();
// BTreeMap → HashMap
let btree: BTreeMap<String, i32> = /* ... */;
let hash: HashMap<String, i32> = btree.into_iter().collect();
Úlohy 5
5a. Máš:
struct Zamestnanec { meno: String, oddelenie: String, plat: u32 }
Napíš funkciu pocet_na_oddeleni(zamestnanci: &[Zamestnanec]) -> BTreeMap<String, usize> — počet ľudí na oddelení, výstup zoradený podľa názvu oddelenia.
5b. Máš vektor slov. Spočítaj výskyt každého slova a výstup zoradeného (BTreeMap). Potom vypíš len slová, ktoré sa vyskytli viac ako 2x.
5c. Máš BTreeMap známok študenta (predmet → známka). Napíš funkcie:
najlepsia_znamka(znamky: &BTreeMap<String, u8>) -> Option<(&String, &u8)>— predmet s najlepšou (najnižšou) známkoupredmety_v_rozsahu(znamky: &BTreeMap<String, u8>, od: &str, do_: &str) -> Vec<(&String, &u8)>— predmety s názvom v danom abecednom rozsahu