Poznáváme C# a Microsoft.NET 26. díl – třídy kolekcí II.

Po minulém seznámení se s kolekcemi a hojně používaným ArrayListem, se dnes podíváme na další užitečné třídy kolekcí. Například na takové, které představují známé datové struktury typu fronta nebo zásobník. Seznámíme se také se s pojmem slovník a s jeho asi nejpoužívanější implementací v podobě hešové tabulky.

Třída Stack

Třída Stack je implementací jedné ze základních datových struktur – zásobníku. Pro ty co o ni ještě neslyšely, tak tato struktura pracuje takzvaným principem last-in-first-out, což v překladu znamená, že prvek, který vložíte jako poslední, bude vyjmut jako první. Prvky jsou do této struktury přidávány pomocí metody Push, a získávány za použití metody Pop.

Metoda Pop, kromě zmíněného získání posledně vloženého prvku, tento prvek ze zásobníku vyjme. Pokud je zásobník prázdný a pokusíme se zavolat tuto metodu, bude vyhozena výjimka System.InvalidOperationException. V situaci, kdy chceme získat posledně vložený prvek, ale nechceme aby tento prvek byl ze zásobníku vyjmut použijeme metodu Peek. Stejně jako u všech tříd kolekcí v základní knihovně tříd .NET frameworku, lze počet obsažených prvků zjistit pomocí instanční vlastnosti Count, která je předepsána v rozhraní ICollection. Následující kód ukazuje použití třídy Stack.

/// <summary>
/// Priklad pouziti tridy Stack.
/// </summary>
public class StackPriklad
{

  public static void Priklad()
  {
    Stack lMujZasobnik = new Stack();
    //pridani prvku do zasobniku
    lMujZasobnik.Push("Prvni");
    lMujZasobnik.Push("Druhy");
    lMujZasobnik.Push("Treti");
    VypisZasobnik(lMujZasobnik);
  }

  /// <summary>
  /// Tato metoda pouze pomoci metody Pop vyjme a vypise
  /// obsah zasobniku.
  /// </summary>
  /// <param name="Zasobnik"></param>
  public static void VypisZasobnik(Stack Zasobnik)
  {
    for (int i = 0; i < Zasobnik.Count;)
      Console.Write("{0}, ",Zasobnik.Pop());
    Console.WriteLine();
  }
}

Výstup bude vypadat takto:

Treti, Druhy, Prvni,

Poznámka: Určitě jste zaznamenali, že implementace metody VypisZasobnik není úplně nejšťastnější, protože při vypisování vyjme všechny prvky ze zásobníku. V Příkladu mi šlo jen u demonstraci funkčnosti metody Pop. Rozumnější řešení by bylo pro výpis obsahu zásobníku využit toho, že třída Stack implementuje rozhraní IEnumerable.

Třída Queue

Tato třída představuje implementaci další známe datové struktury, kterou je takzvaná fronta. Tato datová struktura je založena na principu first-in-first-out, což znamená, že první vložený prvek do struktury bude také jako první vrácen. Prvky jsou do instance této třídy zařazovány metodou Enqueue a k jejich vyřazování slouží metoda Dequeue, která zároveň vrací právě vyřazovaný objekt. Stejně jako u zásobníku, tak v případě, že tuto metodu zavoláme, když je fronta již prázdná, bude vyhozena výjimka System.InvalidOperationException. Pokud chceme jen přečíst prvek, který je na začátku fronty a nechceme jej vyjmout, tak zavoláme metodu Peek. Následující příklad demonstruje použití této kolekce.

/// <summary>
/// Priklad na pouziti kolekce Queue
/// </summary>
public class QueuePriklad
{
  public static void Priklad()
  {
    Queue lMojeFronta = new Queue();
    lMojeFronta.Enqueue("Prvni prvek");
    lMojeFronta.Enqueue("Druhy prvek");
    lMojeFronta.Enqueue("Treti prvek");
    VypisKolekci.VypisHodnoty(lMojeFronta);
    string lPrvek = (string) lMojeFronta.Dequeue();
    Console.WriteLine("Prvni ziskany prvek z fronty je : {0}", lPrvek);
  }
}

Po spuštění tohoto kódu byste měli vidět takovýto výstup:

Prvni prvek, Druhy prvek, Treti prvek,
Prvni ziskany prvek z fronty je : Prvni prvek

K výpisu obsahu fronty jsem použil třídu VypisKolekci, známou s minulého dílu, která využívá implementace rozhraní IEnumerable na třídách kolekcí.

Slovníky a rozhraní IDictionary

Pod kolekci typu slovník si lze představit datovou strukturu, která uchovává své prvky v podobě dvojice klíč-hodnota. Jako společné rozhraní pro tento typ kolekcí je v .NET frameworku použito rozhraní IDictionary. Ve slovnících je dvojice klíč-hodnota použita tak, že se pod unikátním klíčem, nachází určitá hodnota. Z toho logicky plyne, že hodnota ,která v oné dvojici představuje klíč, nemůže nabývat hodnoty null.

Nicméně část hodnota ve dvojici může hodnoty null bez problémů nabývat. Rozhraní IDictionary, mimo jiné obsahuje předpis pro vlastnost Item, která je v jazyce C# implementována formou indexeru. Tato vlastnost zpřístupňuje hodnotu asociované dvojice po zadání klíče, pod kterým je hodnota uložena. Rozhraní IDictionary předepisuje metodu GetEnumerator, kterou již známe s rozhraní IEnumerable. Ostatně rozhraní IDictionary toto rozhraní rozšiřuje.

Avšak třídy implementující rozhraní IDictionary, vracejí po zavolání metody GetEnumerator instanci třídy implementující rozhraní IDictionaryEnumerator, které rozšiřuje rozhraní IEnumerator. Jeho instanční vlastnost Current nyní vrací instance třídy DictionaryEntry, které představují konkrétní asociovanou dvojici. V instanci třídy DictionaryEntry využijeme vlastnost Key pro získaní klíče a vlastnost Value pro získání hodnoty dvojice.

Třída HashTable

Tato třída je asi nejpoužívanější implementací výše zmíněného rozhraní. Organizace asociovaných dvojicí hodnot je založena na hešovém kódu hodnoty představující klíč. Možná se právě někteří z vás pozastavili nad pojmem hešový kód. Hešový kód je číselná hodnota představující instanci objektu. Mělo by platit, že pokud jsou dvě instance stejné, měli by mít stejný hešový kód.

Dobře naimplementovaná hešová funkce by měla zajistit, aby měla každá různá instance i různý hešový kód. Základní implementace tvorby hešového kódu pro instanci se nachází na třídě System.Object a to ve formě metody GetHashCode. Jelikož je tato metoda virtuální, je možné a dokonce doporučené tuto metody na odvozených třídách překrývat vlastní implementací. HashTable neboli hešová tabulka vyhledává právě na základě hešových kódů objektů uložených jako klíče, umožňuje jí to tak efektivní a rychlý způsob vyhledávání, protože se vyhledává podle čísel.

Nové prvky jsou do této struktury přidávány pomocí metody Add, která jako první parametr očekává instanci představující klíč a jako druhý hodnotu, která má být pod klíčem uchována. Odebráni prvku z této kolekce je realizovatelné pomocí metody Remove, které předáme klíč prvku dvojice, kterou chceme odstranit. Užitečné metody jsou také ContainsKey a ContainsValue, pomocí kterých, jak název napovídá, jsme schopni zjistit jestli se v hešové tabulce nachází určitý klíč respektive hodnota. Následující příklad demonstruje použití hešové tabulky.

/// <summary>
/// Ukazka pouziti tridy HashTable
/// </summary>
public class HashTablePriklad
{
  public static void Priklad()
  {
    Hashtable lMojeTable = new Hashtable();
    //pridani prvku do tabulky
    lMojeTable.Add("Prvni", "Prvni prvek");
    lMojeTable.Add("Druhy", "Druhy prvek");
    lMojeTable.Add("Treti", "Treti prvek");
    VypisTabulku(lMojeTable);
    //ziskani hodnoty ulozene pod klicem Prvni
    String lPrvniPrvek = (string)lMojeTable["Prvni"];
    Console.WriteLine("Pod klicem Prvni je v tabulce ulozena hodnota : {0}",lPrvniPrvek);
    Console.WriteLine("V tabulce existuje hodnota pod klicem Druhy : {0}",lMojeTable.ContainsKey("Druhy"));
  }

  public static void VypisTabulku(Hashtable Tabulka)
  {
    //Vlastnost Current pouziteho enumeratoru vraci instance typu DictionaryEntry
    foreach(DictionaryEntry lZaznam in Tabulka)
    {
      Console.WriteLine("Klic : {0} - Hodnota : {1}", lZaznam.Key,lZaznam.Value);
    }
  }
}

Výstup:

Klic : Treti - Hodnota : Treti prvek
Klic : Druhy - Hodnota : Druhy prvek
Klic : Prvni - Hodnota : Prvni prvek
Pod klicem Prvni je v tabulce ulozena hodnota : První prvek
V tabulce existuje hodnota pod klicem Druhy : True

Z důvodu, že hešová tabulka je slovníkem (implementuje rozhraní IDictionary), při průchodu pomocí enumerátoru, tedy i v případě průchodu pomocí cyklu foreach, dostáváme instance třídy DictionaryEntry. V příkladu byl jako typ klíče použit typ String, jehož použití je jednoduché a navíc je na třídě System.String implementována dobrá hešovací funkce.

Zdrojové kódy k příkladům naleznete zde.

Příště se něco dozvíme o použití vlastních poskytovatelů hešových kódů a definici vlastního řazení pro námi definované třídy.

Diskuze (6) Další článek: ATI Crossfire poráží SLI

Témata článku: Software, Microsoft, Programování, Microsoft NET, Peek, Číselná hodnota, TRI, Public, Front, LMO, First, Struktura, Díl, Rychlý způsob, Druhý druh, Základní struktura, Unikátní klíč, Rozhraní, Vložený prvek, Určitá forma, Získaný klíč, Klíč, Remove, Základní princip, Určitý objekt


Určitě si přečtěte

Je lepší hrát na PC, či na konzolích? Nebo jsou i jiné možnosti?

Je lepší hrát na PC, či na konzolích? Nebo jsou i jiné možnosti?

** Jaké jsou výhody a nevýhody hraní na počítači? ** Co mají společného a v čem se liší Xbox One, PS4 a Switch? ** Na čem hrát, když nemáte výkonné PC ani konzoli?

Lukáš Václavík | 125

WindowsFX: Nainstalujte to mamce a taťkovi. Ani nepoznají, že to je Linux

WindowsFX: Nainstalujte to mamce a taťkovi. Ani nepoznají, že to je Linux

** Po dvou měsících tu máme další linuxovou kopii ** Tentokrát jde o imitaci Desítek ** Sestavili ji brazilští geekové nad Ubuntu

Jakub Čížek | 144

10 věcí, které nás štvou na Windows 10 a bohužel asi jen tak nepřestanou

10 věcí, které nás štvou na Windows 10 a bohužel asi jen tak nepřestanou

** Windows 10 je na trhu 5 let, ale pořád má velké rezervy ** Ani desátá velká aktualizace, která vyjde na podzim, je nevyřeší ** Štvou nás Windows Update, Store, Nastavení atd.

Lukáš Václavík | 146


Aktuální číslo časopisu Computer

Megatest mobilů do 8 000 Kč

Test bezdrátových headsetů

Linux i pro začátečníky

Jak surfovat anonymně