Lekce 9: Seznamy, slovníky a další kolekce – Pokročilé struktury dat v C#
V předchozí lekci jsme se seznámili s poli a základními kolekcemi, které nám umožňují uchovávat a spravovat více prvků stejného typu. V této lekci se zaměříme na pokročilejší datové struktury, jako jsou seznamy (List<T>
), slovníky (Dictionary<TKey, TValue>
), a další kolekce, které poskytují větší flexibilitu a efektivitu při práci s daty. Tyto datové struktury jsou důležitými nástroji pro správu a zpracování velkých objemů informací v různých situacích.
Seznamy (List<T>
)
Seznam je jednou z nejpoužívanějších generických kolekcí v C#. Na rozdíl od polí má seznam dynamickou velikost, což znamená, že můžeme přidávat a odstraňovat prvky, aniž bychom museli předem určovat velikost seznamu. Seznamy jsou typově bezpečné, což znamená, že můžeme přidávat pouze prvky určitého typu (specifikovaného při deklaraci seznamu).
Deklarace a inicializace seznamu
Seznam se deklaruje pomocí třídy List<T>
, kde T
je typ prvků, které seznam uchovává. Můžeme seznam buď deklarovat prázdný, nebo ho rovnou naplnit daty při inicializaci.
List<int> cisla = new List<int>(); // Prázdný seznam celých čísel
cisla.Add(10); // Přidání prvku do seznamu
cisla.Add(20); // Přidání dalšího prvku
Případně můžeme seznam inicializovat přímo s hodnotami:
List<string> jmena = new List<string> { "Petr", "Anna", "Josef" };
Přístup k prvkům seznamu
Prvky seznamu jsou indexovány stejně jako v poli, což znamená, že můžeme přistupovat k jednotlivým prvkům pomocí indexů.
string prvniJmeno = jmena[0]; // Výstup: Petr
Iterace přes seznam
Stejně jako u polí můžeme použít smyčky k iteraci přes prvky seznamu.
foreach (string jmeno in jmena)
{
Console.WriteLine(jmeno); // Výpis: Petr, Anna, Josef
}
Přidávání a odebírání prvků
Jednou z hlavních výhod seznamů je, že můžeme dynamicky přidávat nebo odstraňovat prvky.
jmena.Add("Marek"); // Přidá nový prvek na konec seznamu
jmena.Remove("Anna"); // Odebere prvek s hodnotou "Anna"
Slovníky (Dictionary<TKey, TValue>
)
Slovník je datová struktura, která ukládá páry klíč-hodnota. Každý prvek slovníku má unikátní klíč, který slouží k rychlému vyhledání odpovídající hodnoty. Slovníky jsou velmi efektivní pro vyhledávání, když potřebujeme rychle najít hodnotu na základě klíče.
Deklarace a inicializace slovníku
Slovník deklarujeme pomocí třídy Dictionary<TKey, TValue>
, kde TKey
je typ klíče a TValue
je typ hodnoty.
Dictionary<int, string> studenti = new Dictionary<int, string>();
studenti.Add(1, "Petr"); // Přidání klíče 1 s hodnotou "Petr"
studenti.Add(2, "Anna"); // Přidání klíče 2 s hodnotou "Anna"
Můžeme také použít zkrácený zápis pro inicializaci:
Dictionary<string, int> veky = new Dictionary<string, int>
{
{ "Petr", 20 },
{ "Anna", 25 }
};
Přístup k hodnotám ve slovníku
K hodnotám ve slovníku přistupujeme pomocí jejich klíče.
int vek = veky["Petr"]; // Výstup: 20
Pokud klíč ve slovníku neexistuje, můžeme použít metodu TryGetValue
, abychom zabránili vyvolání výjimky.
if (veky.TryGetValue("Josef", out int vekJosefa))
{
Console.WriteLine(vekJosefa);
}
else
{
Console.WriteLine("Josef není ve slovníku.");
}
Iterace přes slovník
Při iteraci přes slovník můžeme použít foreach smyčku k iteraci přes jednotlivé páry klíč-hodnota.
foreach (KeyValuePair<string, int> student in veky)
{
Console.WriteLine($"{student.Key} má {student.Value} let.");
}
Další typy kolekcí
Kromě seznamů a slovníků poskytuje C# mnoho dalších kolekcí, které jsou užitečné v různých scénářích.
Množina (HashSet<T>
)
Množina je kolekce, která neumožňuje duplikáty. Je velmi užitečná, pokud potřebujeme uchovávat unikátní hodnoty a není důležité pořadí prvků.
HashSet<string> mesta = new HashSet<string> { "Praha", "Brno", "Ostrava" };
mesta.Add("Plzeň"); // Přidání nového města
mesta.Add("Praha"); // Tento prvek nebude přidán, protože už existuje
Fronta (Queue<T>
)
Fronta funguje na principu FIFO (First In, First Out), což znamená, že prvky jsou přidávány na konec a odebírány z počátku.
Queue<string> fronta = new Queue<string>();
fronta.Enqueue("Petr");
fronta.Enqueue("Anna");
Console.WriteLine(fronta.Dequeue()); // Výstup: Petr
Zásobník (Stack<T>
)
Zásobník funguje na principu LIFO (Last In, First Out), což znamená, že poslední přidaný prvek je první, který bude odebrán.
Stack<string> zasobnik = new Stack<string>();
zasobnik.Push("Petr");
zasobnik.Push("Anna");
Console.WriteLine(zasobnik.Pop()); // Výstup: Anna
Rozdíly mezi typy kolekcí
Kolekce | Princip | Vhodné pro |
---|---|---|
List<T> | Seznam s dynamickou velikostí | Uchovávání dat, která se často mění |
Dictionary<TKey, TValue> | Páry klíč-hodnota | Rychlé vyhledávání na základě unikátního klíče |
HashSet<T> | Unikátní prvky, bez duplikátů | Uchovávání unikátních hodnot |
Queue<T> | FIFO – první dovnitř, první ven | Situace, kdy potřebujeme zpracovat prvky ve stejném pořadí, jak byly přidány |
Stack<T> | LIFO – poslední dovnitř, první ven | Zpracování prvků v obráceném pořadí |
Výkon a složitost
Různé kolekce mají různé charakteristiky, pokud jde o výkon a složitost operací. Zatímco seznamy mají efektivní přístup k prvkům pomocí indexu (O(1)), operace přidávání nebo odebírání prvků může být méně efektivní, pokud se jedná o velké množství dat. Na druhou stranu slovníky poskytují velmi rychlé vyhledávání na základě klíče (O(1)), ale mohou mít větší paměťové nároky.
Složitost běžných operací:
Operace | List<T> | Dictionary<TKey, TValue> | Queue<T> | Stack<T> |
---|---|---|---|---|
Přístup k prvku | O(1) | O(1) | N/A | N/A |
Přidání prvku | O(1) | O(1) | O(1) | O(1) |
Odebrání prvku | O(n) | O(1) | O(1) | O(1) |
Vyhledání prvku | O(n) | O(1) | O(n) | O(n) |
Závěr
Seznamy, slovníky a další kolekce jsou nezbytné nástroje pro správu dat v C#. V této lekci jsme se naučili, jak pracovat s pokročilými datovými strukturami, jako jsou List, Dictionary, HashSet, Queue a Stack. Každý z těchto typů kolekcí má své specifické vlastnosti a je vhodný pro různé scénáře. Správný výběr datové struktury je klíčový pro efektivitu a výkon aplikace.