277 lines
7.5 KiB
Markdown
277 lines
7.5 KiB
Markdown
# BTreeMap — krok za krokom
|
|
|
|
Každá kapitola: prečítaj, pozri príklady, urob úlohy. Až potom choď ďalej.
|
|
|
|
```rust
|
|
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` |
|
|
|
|
```rust
|
|
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:
|
|
```rust
|
|
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:
|
|
|
|
```rust
|
|
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:
|
|
```rust
|
|
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
|
|
|
|
```rust
|
|
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:
|
|
```rust
|
|
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:
|
|
```rust
|
|
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ľúč:
|
|
|
|
```rust
|
|
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á:
|
|
```rust
|
|
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áš:
|
|
```rust
|
|
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ámkou
|
|
- `predmety_v_rozsahu(znamky: &BTreeMap<String, u8>, od: &str, do_: &str) -> Vec<(&String, &u8)>` — predmety s názvom v danom abecednom rozsahu
|