NOVINKA - Online rekvalifikační kurz Python programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 3 - Spojový seznam v C#

V minulé lekci, Seznam (list) pomocí pole v C#, jsme si představili seznamy (listy) a detailně jsme popsali seznam pomocí pole a třídu List.

Dnes se v C# .NET tutoriálu zaměříme na druhý typ seznamu, kterým je spojový seznam.

Spojové seznamy

Druhou možností vytvoření seznamu s proměnným počtem prvků jsou tzv. spojové seznamy. Ty již s polem vůbec nepracují a jsou založené na odlišném principu. Jednotlivé prvky v listu jsou v paměti různě rozházené (nejsou tedy již uložené za sebou) a po sobě jdoucí prvky na sebe odkazují. Můžeme si to představit jako takový řetězec, kdy první prvek ukazuje na druhý, druhý na třetí a tak dále. Prvky z minulého příkladu bychom si ve spojovém seznamu mohli představit např. takto:

Jednosměrný spojový seznam v C# .NET - Kolekce a LINQ v C# .NET

Takovému spojovému seznamu se říká jednosměrný (Singly Linked List). Pokud nemáme nějaký vážný důvod šetřit pamětí, obvykle na sebe dva po sobě jdoucí prvky ukazují navzájem (tedy i druhý na první a tak dále). Pak hovoříme o obousměrném spojovém seznamu (Doubly Linked List). Ten by v našem případě vypadal nějak takto:

Obousměrný spojový seznam v C# .NET - Kolekce a LINQ v C# .NET

U spojových seznamů jsme přišli o možnost rychle přistoupit k prvku podle jeho indexu, a to kvůli tomu, že prvky již nejsou v paměti za sebou. Neexistuje způsob, jak efektivně přeskočit rovnou např. na stý prvek a přečíst jeho hodnotu. Když chceme ke stému prvku přistoupit, musíme jít z prvního prvku na druhý, z druhého na třetí a tak dále až do stovky. Časová složitost čtení i zápisu na index tedy závisí na počtu prvků v listu.

Někdy však nepotřebujeme prvky indexovat a v tu chvíli se tato kolekce stává velmi výhodnou. Již na začátku jsme si řekli, že s polem vůbec nepracujeme. Již nejsme nijak omezeni délkou seznamu a položky můžeme za běhu programu přidávat či mazat tak dlouho, dokud nám bude stačit paměť. Poměrně dobře můžeme mazat i prvky uprostřed seznamu nebo vkládat nové prvky mezi existující. U pole bylo vložení prvku možné pouze tak, že jsme všechny prvky napravo posunuli a vytvořili tak místo pro nový prvek. To nás stálo nemalý výpočetní čas, který závisel na počtu prvků. Ve spojovém seznamu prvek pouze naodkazujeme mezi dva existující, ostatních prvků se změna nedotkne.

Máme tedy efektivní vkládání a mazání prvků za cenu neefektivního přístupu k indexům. Tak už to u datových struktur a algoritmů vůbec bývá, něco za něco :)

Vidíme, že spojový seznam a seznam přes pole se velmi liší. Budeme-li často přistupovat k prvkům pomocí indexu, bude spojový seznam katastrofou. Budeme-li naopak prvky často vkládat nebo mazat uprostřed kolekce, spojový seznam si s tím hravě poradí, avšak list s polem by byl extrémně pomalý.

LinkedList

Spojový seznam je v .NET reprezentovaný generickou kolekcí LinkedList. Jedná se o spojový seznam obousměrný, jednosměrný spojový seznam v .NET nenajdeme. Mohli bychom si ho naprogramovat, ale nemá to příliš význam, jelikož se s ním hůře pracuje a úspora paměti je mizivá.

LinkedList neobsahuje rovnou naše prvky, jako tomu bylo u seznamu List, ale jsou v něm uloženy položky typu LinkedListNode. Jsou to uzly, které na sebe navzájem ukazují (odkazují na sebe, chcete-li) a disponují vlastností Value. Právě v té je teprve uložen náš prvek, který je uzlem obalen. Uzel tak dodává našemu prvku ony vazby na prvky okolní. Ukažme si metody, které má LinkedList oproti klasickému List navíc:

  • AddAfter() – Přidá nový prvek za daný prvek.
  • AddBefore() – Přidá nový prvek před daný prvek.
  • AddFirst() – Přidá nový prvek na začátek seznamu.
  • AddLast() – Přidá nový prvek na konec seznamu.
  • First – Vlastnost vracející první prvek.
  • Last – Vlastnost vracející poslední prvek.
  • RemoveFirst() – Odstraní první prvek.
  • RemoveLast() – Odstraní poslední prvek.

Příklad

Vyzkoušejme si podobný příklad jako u listu:

LinkedList<int> seznam = new LinkedList<int>();
LinkedListNode<int> hlava = seznam.AddFirst(5);
seznam.AddAfter(hlava, 10);
Console.WriteLine(seznam.First.Value);
Console.WriteLine(seznam.First.Next.Value);

Výstup programu:

Konzolová aplikace
5
10

Vytvoříme nový spojový seznam typu int, přidáme první prvek a uložíme si ho jako hlavu. Za hlavu přidáme další prvek. Nakonec vypíšeme první prvek a prvek po prvním prvku (tedy ten druhý).

Zkusme si ještě ono rychlé vkládání a mazání prvků:

// inicializace a naplnění spojového seznamu
LinkedList<int> seznam = new LinkedList<int>();
seznam.AddLast(1);
seznam.AddLast(2);
LinkedListNode<int> prostredni = seznam.AddLast(3);
seznam.AddLast(4);
seznam.AddLast(5);

// přidávání a mazání veprostřed seznamu
seznam.AddAfter(prostredni, 32);
seznam.AddAfter(prostredni, 31);
seznam.Remove(prostredni);

// výpis seznamu
foreach (int i in seznam)
    Console.Write("{0}, ", i);

Console.ReadKey();

Výstup:

Konzolová aplikace
1, 2, 31, 32, 4, 5,

Práce se spojovým seznamem je kvůli uzlům o něco komplikovanější než s listem a většinou používáme spíše List. Po „spojáku“ sáhneme hlavně v případě, kdy chceme často vkládat a mazat prvky uprostřed seznamu, což by u listu bylo velmi pomalé.

Dovolte ještě poznámku, než listy úplně opustíme. Ve starých zdrojových kódech můžeme narazit na kolekci StringCollection. Ta suplovala za List<string> v dobách, kdy kolekce v .NET nebyly generické. Dnes již není důvod tuto třídu používat a způsobuje spíše zmatení.

Dnes to bylo trochu kratší, abychom na konci nezačínali nové téma.

V příští lekci, Vícerozměrná pole v C# .NET, si představíme vícerozměrná pole.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 591x (22.95 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

Předchozí článek
Seznam (list) pomocí pole v C#
Všechny články v sekci
Kolekce a LINQ v C# .NET
Přeskočit článek
(nedoporučujeme)
Vícerozměrná pole v C# .NET
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
380 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity