Files
JR-priprava-na-skusku/priprava/rust_priprava5.md
2026-02-26 18:59:33 +01:00

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