Stapels en wachtrijen

Tot dusver hebben we gekeken naar collecties die een zeer eenvoudige gegevensopslag bieden, in wezen abstracties over een array. In dit gedeelte gaan we kijken naar wat er gebeurt als we enkele zeer basale gedragingen toevoegen die het nut van de collecties volledig veranderen.

stack

Een stapel is een verzameling die objecten terugstuurt naar de beller in een Last-in-First-Out (LIFO) -patroon. Wat dit betekent is dat het laatste object dat aan de verzameling is toegevoegd, het eerste object is dat wordt geretourneerd.

Stacks verschillen van lijst en array-achtige collecties. Ze kunnen niet rechtstreeks worden geïndexeerd, objecten worden op verschillende manieren toegevoegd en verwijderd en de inhoud ervan is ondoorzichtiger dan lijsten en matrices. Wat ik hiermee bedoel is dat hoewel een lijst-gebaseerde verzameling een Bevat-methode biedt, een stapel dat niet doet. Bovendien is een stapel niet opsombaar. Om te begrijpen waarom dit is, laten we eens kijken naar wat een stapel is en hoe het gebruik van een stapel deze verschillen stuurt.

Een van de meest voorkomende analogieën voor een stapel is de restaurantbordenstapel. Dit is een eenvoudig veerbelast apparaat waarop schone platen worden gestapeld. De veer zorgt ervoor dat, ongeacht het aantal platen in de stapel, de bovenplaat gemakkelijk toegankelijk is. Schone platen worden toegevoegd aan de bovenkant van de stapel en wanneer een klant een plaat verwijdert, verwijdert hij of zij de bovenste plaat (de laatst toegevoegde plaat).

We beginnen met een leeg bordenrek.

Een lege platenstapel (de veer houdt geen platen vast)

En dan voegen we een rode, een blauwe en een groene plaat toe aan het rek in die volgorde.

Het belangrijkste punt om te begrijpen is dat wanneer nieuwe platen worden toegevoegd, deze aan de bovenkant van de stapel worden toegevoegd. Als een klant een bord ophaalt, krijgt hij of zij de laatst toegevoegde plaat (de groene plaat). De volgende klant krijgt de blauwe plaat en uiteindelijk wordt de rode plaat verwijderd.

Nu we begrijpen hoe een stapel werkt, laten we een paar nieuwe termen definiëren. Wanneer een item aan de stapel wordt toegevoegd, wordt het "ingedrukt" bij het gebruik van de Duwen methode. Wanneer een item uit de stapel wordt verwijderd, wordt het "weggekropen" met behulp van de Knal methode. Het bovenste item in de stapel, het meest recent toegevoegd, kan worden "gekeken" bij het gebruik van de Kijkje methode. Met Gluren kunt u het item bekijken zonder het van de stapel te verwijderen (net zoals de klant bij het bordenrek de kleur van de bovenplaat zou kunnen zien). Laten we met deze voorwaarden in ons achterhoofd kijken naar de implementatie van een stack klasse.

Klasse definitie

De stack klasse definieert Duwen, Knal, en Kijkje methoden, a tellen eigendom, en gebruikt de LinkedList klasse om de waarden in de stapel op te slaan.

public class Stack LinkedList _items = new LinkedList (); public void Push (T-waarde) gooi nieuwe NotImplementedException ();  public T Pop () gooi new NotImplementedException ();  public T Peek () gooi nieuwe NotImplementedException ();  openbare int Graaf krijgen;  

Duwen

Gedrag Voegt een item toe aan de bovenkant van de stapel.
Prestatie O (1)

Omdat we een gekoppelde lijst gebruiken als onze back-upwinkel, hoeven we alleen maar het nieuwe item aan het einde van de lijst toe te voegen.

public void Push (T-waarde) _items.AddLast (waarde);  

Knal

Gedrag Verwijdert en retourneert het laatste item dat aan de stapel is toegevoegd. Als de stapel leeg is, InvalidOperationException wordt gegooid.
Prestatie O (1)

Duwen voegt items toe aan de achterkant van de lijst, dus we "poppen" ze vanaf de achterkant. Als de lijst leeg is, wordt een uitzondering gegenereerd.

public T Pop () if (_items.Count == 0) gooi new InvalidOperationException ("De stapel is leeg");  T result = _items.Tail.Value; _items.RemoveLast (); terugkeer resultaat;  

Kijkje

Gedrag Retourneert het laatste item dat aan de stapel is toegevoegd maar laat het item op de stapel. Als de stapel leeg is, InvalidOperationException wordt gegooid.
Prestatie O (1)
public T Peek () if (_items.Count == 0) gooi new InvalidOperationException ("De stapel is leeg");  return _items.Tail.Value;  

tellen

Gedrag Retourneert het aantal items in de stapel.
Prestatie O (1)

Aangezien de stack een ondoorzichtige gegevensstructuur moet zijn, waarom hebben we dan een tellen eigendom? Weten of een stapel leeg is (Graaf == 0) is erg handig, vooral sindsdien Knal werpt een uitzondering wanneer de stapel leeg is.

public int Count krijg return _items.Count;  

Voorbeeld: RPN-rekenmachine

Het klassieke stack-voorbeeld is de Reverse Polish Notation (RPN) -calculator.

RPN-syntaxis is vrij eenvoudig. Het gebruikt:

in plaats van de traditionele:

.

Met andere woorden, in plaats van '4 + 2' te zeggen, zouden we '4 2 +' zeggen. Als u de historische betekenis van de syntaxis van RPN wilt begrijpen, raad ik u aan naar Wikipedia of uw favoriete zoekmachine te gaan..

De manier waarop RPN wordt geëvalueerd en de reden dat een stapel zo handig is bij het implementeren van een RPN-rekenmachine, is te zien in het volgende algoritme:

voor elke invoerwaarde als de waarde een geheel getal is, duwt u de waarde aan naar de operandstapel anders als de waarde een operator is pop de linker- en rechterwaarden van de stapel evalueren de operator duwt het resultaat naar de stapel pop antwoord van stapel. 

Dus gezien de invoertekenreeks "4 2 +", zouden de bewerkingen zijn:

druk (4) druk (2) druk (pop () + pop ()) 

De stapel bevat nu een enkele waarde: zes (het antwoord).

Het volgende is een volledige implementatie van een eenvoudige rekenmachine die een vergelijking (bijvoorbeeld "4 2 +") van de console-invoer leest, de invoer op elke spatie splitst (["4", "2" en "+"]) , en voert het RPN-algoritme op de invoer uit. De lus gaat door totdat de invoer het woord "quit" is.

void RpnLoop () while (true) Console.Write (">"); string input = Console.ReadLine (); if (input.Trim (). ToLower () == "quit") break;  // De stapel gehele getallen die nog niet zijn geopereerd. Stapelwaarden = nieuwe stapel (); foreach (string token in input.Split (new char [] ")) // Als de waarde een geheel getal is ... int value; if (int.TryParse (token, out value)) // ... push it to de stack. values.Push (waarde); else // Anders evalueren de expressie ... int rhs = values.Pop (); int lhs = values.Pop (); // ... en laat het resultaat terug naar de stapel. switch (token) case "+": values.Push (lhs + rhs); break; case "-": values.Push (lhs - rhs); break; case "*": values.Push (lhs * rhs) ; break; case "/": values.Push (lhs / rhs); break; case "%": values.Push (lhs% rhs); break; standaard: throw new ArgumentException (string.Format ("Unrecognized token:  0 ", token)); // Het laatste item op de stapel is het resultaat. Console.WriteLine (values.Pop ()); 

Wachtrij

Wachtrijen lijken veel op stacks: ze bieden een ondoorzichtige verzameling waaruit objecten kunnen worden toegevoegd (in de wachtrij worden geplaatst) of verwijderd (verwijderd) op een manier die waarde toevoegt aan een op lijsten gebaseerde verzameling.

Wachtrijen zijn een First-in-First-Out (FIFO) -collectie. Dit betekent dat items uit de wachtrij worden verwijderd in dezelfde volgorde waarin ze zijn toegevoegd. U kunt een wachtrij zoals een lijn bij een kassa in de winkel zien. Tegenstanders komen in de rij en worden gerepareerd in de volgorde waarin ze aankomen.

Wachtrijen worden vaak gebruikt in toepassingen om een ​​buffer te bieden om items toe te voegen voor toekomstige verwerking of om ordelijke toegang tot een gedeelde bron te bieden. Als een database bijvoorbeeld slechts één verbinding kan verwerken, kan een wachtrij worden gebruikt om te zorgen dat threads hun beurt (in volgorde) wachten om toegang te krijgen tot de database.

Klasse definitie

De Wachtrij, zoals de stack, wordt ondersteund door een LinkedList. Bovendien biedt het de methoden enqueue (om items toe te voegen), dequeue (om items te verwijderen), Kijkje, en tellen. Net zoals stack, het zal niet worden behandeld als een verzameling voor algemene doeleinden, wat betekent dat het niet wordt uitgevoerd ICollection.

openbare klassenwachtrij LinkedList _items = nieuwe LinkedList (); public void Enqueue (T-waarde) gooi nieuwe NotImplementedException ();  public T Dequeue () gooi new NotImplementedException ();  public T Peek () gooi nieuwe NotImplementedException ();  openbare int Graaf krijgen;  

enqueue

Gedrag Voegt een item toe aan het einde van de wachtrij.
Prestatie O (1)

Met deze implementatie wordt het item toegevoegd aan het begin van de gekoppelde lijst. Het item kan net zo goed aan het einde van de lijst worden toegevoegd. Het enige dat er echt toe doet, is dat items aan het einde van de lijst worden geplaatst en uit de andere worden verwijderd (FIFO). Merk op dat dit het tegenovergestelde is van de Stack-klasse waar items worden toegevoegd en verwijderd van hetzelfde uiteinde (LIFO).

Public void Enqueue (T-waarde) _items.AddFirst (waarde);  

dequeue

Gedrag Verwijdert en retourneert het oudste item uit de wachtrij. Een InvalidOperationException wordt weggegooid als de wachtrij leeg is.
Prestatie O (1)

Sinds enqueue heeft het item toegevoegd aan het begin van de lijst, dequeue moet het item aan het einde van de lijst verwijderen. Als de wachtrij geen items bevat, wordt een uitzondering gegenereerd.

public T Dequeue () if (_items.Count == 0) gooi new InvalidOperationException ("De wachtrij is leeg");  T last = _items.Tail.Value; _items.RemoveLast (); terugkeer laatste;  

Kijkje

Gedrag Retourneert het volgende item dat zou worden geretourneerd als Dequeue werd aangeroepen. De wachtrij blijft ongewijzigd. Een ongeldige bewerkingsexception wordt gegenereerd als de wachtrij leeg is.
Prestatie O (1)
public T Peek () if (_items.Count == 0) gooi new InvalidOperationException ("De wachtrij is leeg");  return _items.Tail.Value;  

tellen

Gedrag Retourneert het aantal items dat momenteel in de wachtrij staat. Retourneert 0 als de wachtrij leeg is.
Prestatie O (1)
public int Count krijg return _items.Count;  

Deque (Double-Ended Queue)

Een wachtrij met twee einden, of deque, breidt het gedrag van de wachtrij uit door toe te staan ​​dat items aan beide zijden van de wachtrij worden toegevoegd of verwijderd. Dit nieuwe gedrag is nuttig in verschillende probleemdomeinen, met name taak- en threadplanning. Het is ook over het algemeen nuttig voor het implementeren van andere datastructuren. We zullen een voorbeeld zien van het gebruik van een deque om later een andere datastructuur te implementeren.

Klasse definitie

De Deque klasse wordt ondersteund door een dubbel gelinkte lijst. Dit stelt ons in staat om items aan de voor- of achterkant van de lijst toe te voegen en te verwijderen en toegang te krijgen tot de Eerste en Laatste eigenschappen. De belangrijkste wijzigingen tussen de klasse Wachtrij en de klasse Deque zijn dat de enqueue, dequeue, en Kijkje methoden zijn verdubbeld Eerste en Laatste varianten.

public class Deque LinkedList _items = new LinkedList (); public void EnqueueFirst (T-waarde) gooi new NotImplementedException ();  public void EnqueueLast (T-waarde) gooi nieuwe NotImplementedException ();  public T DequeueFirst () gooi nieuwe NotImplementedException ();  public T DequeueLast () gooi nieuwe NotImplementedException ();  public T PeekFirst () gooi nieuwe NotImplementedException ();  public T PeekLast () gooi new NotImplementedException ();  openbare int Graaf krijgen;  

enqueue

EnqueueFirst

Gedrag Voegt de opgegeven waarde toe aan de kop van de wachtrij. Dit is het volgende item dat wordt uitgeleend door DequeueFirst.
Prestatie O (1)
public void EnqueueFirst (T-waarde) _items.AddFirst (waarde);  

EnqueueLast

Gedrag Voegt de opgegeven waarde toe aan de staart van de wachtrij. Dit is het volgende item dat wordt uitgeleend door DequeueLast.
Prestatie O (1)
public void EnqueueLast (T-waarde) _items.AddLast (value);  

dequeue

DequeueFirst

Gedrag Verwijdert en retourneert het eerste item in de deque. Een ongeldige bewerkingsexception wordt gegenereerd als de deque leeg is.
Prestatie O (1)
public T DequeueFirst () if (_items.Count == 0) gooi new InvalidOperationException ("DequeueFirst called when deque empty is");  T temp = _items.Head.Value; _items.RemoveFirst (); terugkeer temp;  

DequeueLast

Gedrag Verwijdert en retourneert het laatste item in de deque. Een ongeldige bewerkingsexception wordt gegenereerd als de deque leeg is.
Prestatie O (1)
public T DequeueLast () if (_items.Count == 0) gooi new InvalidOperationException ("DequeueLast called when deque empty is");  T temp = _items.Tail.Value; _items.RemoveLast (); terugkeer temp;  

PeekFirst

Gedrag Retourneert het eerste item in de deque maar laat de verzameling ongewijzigd. Een ongeldige bewerkingsexception wordt gegenereerd als de deque leeg is.
Prestatie O (1)
public T PeekFirst () if (_items.Count == 0) gooi new InvalidOperationException ("PeekFirst called when deque empty is");  return _items.Head.Value;  

PeekLast

Gedrag Retourneert het laatste item in de deque maar laat de verzameling ongewijzigd. Een ongeldige bewerkingsexception wordt gegenereerd als de deque leeg is.
Prestatie O (1)
public T PeekLast () if (_items.Count == 0) gooi new InvalidOperationException ("PeekLast called when deque empty is");  return _items.Tail.Value;  

tellen

Gedrag Retourneert het aantal items dat zich momenteel in de deque bevindt, of 0 als de deque leeg is.
Prestatie O (1)
public int Count krijg return _items.Count;  

Voorbeeld: een stapel implementeren

Deques worden vaak gebruikt om andere datastructuren te implementeren.

We hebben een stapel geïmplementeerd met een LinkedList, dus laten we nu kijken naar een geïmplementeerd met een Deque.

Je vraagt ​​je misschien af ​​waarom ik ervoor zou kiezen om een ​​te implementeren stack met behulp van een Deque liever dan een LinkedList. De reden is een van de prestaties en hergebruik van code. Een gelinkte lijst heeft de kosten van per-node overhead en verminderde datalocatie - de items worden in de heap toegewezen en de geheugenlocaties zijn mogelijk niet in de buurt van elkaar, waardoor er meer cache-missers en paginafouten optreden bij de CPU en geheugenhardware levels. Een beter presterende implementatie van een wachtrij gebruikt mogelijk een array als het back-uparchief in plaats van een lijst. Dit zou leiden tot minder overheadkosten per knooppunt en zou de prestaties kunnen verbeteren door een aantal problemen met de locatie aan te pakken.

Implementatie van een stack of Wachtrij als een array echter een complexere implementatie is. Door de Deque op deze meer complexe manier en door het te gebruiken als de basis voor andere datastructuren, kunnen we de prestatievoordelen voor alle structuren realiseren, terwijl we de code slechts eenmaal hoeven te schrijven. Dit versnelt de ontwikkelingstijd en verlaagt de onderhoudskosten.

We zullen kijken naar een voorbeeld van een Deque als een array verderop in dit gedeelte, maar laten we eerst eens kijken naar een voorbeeld van een stack geïmplementeerd met behulp van een Deque.

public class Stack Deque _items = new Deque (); public void Push (T-waarde) _items.EnqueueFirst (waarde);  public T Pop () return _items.DequeueFirst ();  public T Peek () return _items.PeekFirst ();  public int Count krijg return _items.Count;  

Merk op dat alle foutcontroles nu worden uitgesteld naar de Deque en elke optimalisatie of bugfix die is gemaakt naar de Deque zal automatisch van toepassing zijn op de stack klasse. Implementatie van een Wachtrij is net zo eenvoudig en als zodanig overblijft als een oefening voor de lezer.

Array Backing Store

Zoals eerder vermeld, zijn er voordelen verbonden aan het gebruik van een array in plaats van een gekoppelde lijst als de back-upopslag voor de Deque (een deque van gehele getallen). Conceptueel lijkt dit eenvoudig, maar er zijn eigenlijk verschillende zaken die moeten worden aangepakt om dit te laten werken.

Laten we een aantal van deze problemen grafisch bekijken en dan kijken hoe we ze kunnen aanpakken. Houd daarbij rekening met de problemen van het groeibeleid die zijn besproken in de sectie ArrayList en dat dezelfde problemen hier gelden.

Wanneer de verzameling is gemaakt, is deze een array van 0-lengte. Laten we eens kijken naar hoe sommige acties de interne array beïnvloeden. Let er bij het doorlezen op dat de groene "h" en rode "t" in de figuren respectievelijk verwijzen naar "head" en "tail". De kop en de staart zijn de array-indices die de eerste en laatste items in de wachtrij aangeven. Als we items toevoegen en verwijderen, wordt de interactie tussen hoofd en staart duidelijker.

Deque deq = new Deque (); deq.EnqueueFirst (1); 
Een waarde toevoegen aan de voorkant van de deque
deq.EnqueueLast (2); 
Een waarde toevoegen aan het einde van de deque
deq.EnqueueFirst (0); 
Een andere waarde toevoegen aan de voorkant van de deque; de hoofdindex wikkelt rond

Let op wat er op dit punt is gebeurd. De kopindex is rond het einde van de array gewikkeld. Nu het eerste item in de deque, wat zou worden geretourneerd door DequeueFirst, is de waarde bij reeksindex drie (nul).

deq.EnqueueLast (3); 
Een waarde toevoegen aan het einde van de deque

Op dit punt is de array gevuld. Wanneer een ander item wordt toegevoegd, gebeurt het volgende:

  1. Het groeibeleid bepaalt de grootte van de nieuwe array.
  2. De items worden van kop tot staart gekopieerd naar de nieuwe array.
  3. Het nieuwe item wordt toegevoegd.
    1. EnqueueFirst - Het item wordt toegevoegd op index nul (de kopieerbewerking laat dit open).
    2. EnqueueLast - Het item wordt toegevoegd aan het einde van de array.
deq.EnqueueLast (4); 
Een waarde toevoegen aan het einde van de uitgebreide deque

Laten we nu eens kijken wat er gebeurt als items uit de Deque worden verwijderd.

deq.DequeueFirst (); 
Het eerste item verwijderen uit de uitgebreide deque
deq.DequeueLast (); 
Het laatste item uit de uitgebreide deque verwijderen

Het kritieke punt om op te merken is dat, ongeacht de capaciteit van de interne array, de logische inhoud van de Deque de items zijn van de index van de kop tot de staartindex, rekening houdend met de noodzaak om rond te wikkelen aan het einde van de array. Een array die het gedrag van het omwikkelen van het hoofd naar de staart biedt, staat vaak bekend als een circulaire buffer.

Met dit inzicht in hoe de array-logica werkt, laten we direct de code in duiken.

Klasse definitie

De array-gebaseerde Deque-methoden en -eigenschappen zijn dezelfde als op basis van de lijst, dus ze worden hier niet herhaald. De lijst is echter vervangen door een array en er zijn nu drie eigenschappen die de grootte, kop en staartinformatie bevatten.

public class Deque T [] _items = new T [0]; // Het aantal items in de wachtrij. int _size = 0; // De index van het eerste (oudste) item in de wachtrij. int _head = 0; // De index van het laatste (nieuwste) item in de wachtrij. int _tail = -1; ... 

enqueue

Groeipolitiek

Wanneer de interne array moet groeien, moet het algoritme om de array te vergroten, de array-inhoud te kopiëren en de interne indexwaarden bij te werken, worden uitgevoerd. De enqueue methode voert die bewerking uit en wordt door beide aangeroepen EnqueueFirst en EnqueueLast. De startingIndex parameter wordt gebruikt om te bepalen of de array-slot op index nul open moet (in geval van EnqueueFirst).

Besteed specifieke aandacht aan de manier waarop de gegevens worden uitgepakt in gevallen waarin de stap van kop naar staart moet worden uitgevoerd rond het einde van de array terug naar nul.

private void allocateNewArray (int startingIndex) int newLength = (_size == 0)? 4: _maat * 2; T [] newArray = nieuwe T [newLength]; if (_size> 0) int targetIndex = startIndex; // Kopieer de inhoud ... // Als de array geen wrapping bevat, kopieert u gewoon het geldige bereik. // Anders kopiëren van kop tot eind van de array en vervolgens van 0 naar de staart. // Als de staart minder is dan het hoofd, hebben we gewikkeld. als (_tail < _head)  // Copy the _items[head]… _items[end] -> newArray [0] ... newArray [N]. voor (int index = _head; index < _items.Length; index++)  newArray[targetIndex] = _items[index]; targetIndex++;  // Copy _items[0]… _items[tail] -> newArray [N + 1] ... voor (int index = 0; index <= _tail; index++)  newArray[targetIndex] = _items[index]; targetIndex++;   else  // Copy the _items[head]… _items[tail] -> newArray [0] ... newArray [N] voor (int index = _head; index <= _tail; index++)  newArray[targetIndex] = _items[index]; targetIndex++;   _head = startingIndex; _tail = targetIndex - 1; // Compensate for the extra bump.  else  // Nothing in the array. _head = 0; _tail = -1;  _items = newArray;  

EnqueueFirst

Gedrag Voegt de opgegeven waarde toe aan de kop van de wachtrij. Dit is het volgende item dat wordt uitgeleend door DequeueFirst.
Prestatie O (1) in de meeste gevallen; O (n) wanneer groei nodig is.
public void EnqueueFirst (T item) // Als de array moet groeien. if (_items.Length == _size) allocateNewArray (1);  // Omdat we weten dat de array niet vol is en _head groter is dan 0, // weten we dat de sleuf voor het hoofd open is. if (_head> 0) _head--;  else // Anders moeten we ons omdraaien naar het einde van de array. _head = _items.Length - 1;  _items [_head] = item; _size ++;  

EnqueueLast

Gedrag Voegt de opgegeven waarde toe aan de staart van de wachtrij. Dit is het volgende item dat wordt uitgeleend door DequeueLast.
Prestatie O (1) in de meeste gevallen; O (n) wanneer groei nodig is.
public void EnqueueLast (T item) // Als de array moet groeien. if (_items.Length == _size) allocateNewArray (0);  // Nu hebben we een array van de juiste grootte en kunnen we ons concentreren op wrapping-problemen. // Als _tail aan het einde van de array is, moeten we ons omdraaien. if (_tail == _items.Length - 1) _tail = 0;  else _tail ++;  _items [_tail] = item; _size ++;  

dequeue

DequeueFirst

Gedrag Verwijdert en retourneert het eerste item in de deque. Een ongeldige bewerkingsexception wordt gegenereerd als de deque leeg is.
Prestatie O (1)
public T DequeueFirst () if (_size == 0) gooi new InvalidOperationException ("The deque is empty");  T-waarde = _items [_head]; if (_head == _items.Length - 1) // Als de kop op de laatste index van de array staat, wikkel deze dan om. _head = 0;  else // Ga naar het volgende slot. _head ++;  _size--; winstwaarde;  

DequeueLast

Gedrag Verwijdert en retourneert het laatste item in de deque. Een ongeldige bewerkingsexception wordt gegenereerd als de deque leeg is.
Prestatie O (1)
public T DequeueLast () if (_size == 0) gooi new InvalidOperationException ("De deque is empty");  T-waarde = _items [_tail]; if (_tail == 0) // Als de staart zich bij de eerste index in de array bevindt, wikkel deze dan om. _tail = _items.Length - 1;  else // Ga naar het vorige slot. _staart--;  _size--; winstwaarde;  

PeekFirst

Gedrag Retourneert het eerste item in de deque maar laat de verzameling ongewijzigd. Een InvalidOperationException wordt gegooid als de kaart leeg is.
Prestatie O (1)
public T PeekFirst () if (_size == 0) gooi new InvalidOperationException ("The deque is empty");  return _items [_head];  

PeekLast

Gedrag Retourneert het laatste item in de deque maar laat de verzameling ongewijzigd. Een InvalidOperationException wordt gegooid als de kaart leeg is.
Prestatie O (1)
public T PeekLast () if (_size == 0) gooi new InvalidOperationException ("The deque is empty");  return _items [_tail];  

tellen

Gedrag Retourneert het aantal items dat zich momenteel in de boog bevindt of 0 als de boog leeg is.
Prestatie O (1)
public int Count krijg return _size;  

Volgende

Hiermee is het vierde deel over stapels en wachtrijen voltooid. Vervolgens gaan we verder met de binaire zoekboom.