Arrays zijn geweldig als je de grootte van je data vooraf kent. Maar wat als data onvoorspelbaar binnenkomt - een stroom sensorwaarden, een wachtrij met taken voor een AI, of een gespreksgeschiedenis die bij elk bericht groeit? Dan heb je structuren nodig die soepel mee groeien en krimpen.
Hier komen linked lists, stacks en queues in beeld - het dynamische trio.
Een linked list slaat items op als een keten van knooppunten (nodes). Elk knooppunt bevat twee dingen: de data zelf en een pointer (verwijzing) naar het volgende knooppunt.
[data: "A" | next: →] → [data: "B" | next: →] → [data: "C" | next: null]
Anders dan bij arrays staan knooppunten niet naast elkaar in het geheugen. Ze kunnen overal staan - de pointer vertelt je simpelweg waar het volgende knooppunt te vinden is.
| Operatie | Array | Linked List | |----------|-------|-------------| | Toegang via index | O(1) ⚡ | O(n) 🐢 | | Invoegen aan begin | O(n) 🐢 | O(1) ⚡ | | Invoegen in midden | O(n) 🐢 | O(1)* ⚡ | | Verwijderen uit midden | O(n) 🐢 | O(1)* ⚡ | | Geheugengebruik | Compact | Extra (pointers) |
*Zodra je de positie gevonden hebt - het vinden is nog steeds O(n).
De tabbalk van je browser laat je vrij tabbladen openen, sluiten en herschikken. Zou een array of een linked list beter passen voor het beheren van open tabbladen? Bedenk wat er gebeurt als je een tabblad in het midden sluit.
Een stack werkt precies als een stapel borden: je legt bovenop en pakt van bovenaf. Het laatst geplaatste item is het eerste dat eraf gaat.
Sign in to join the discussion
Push "A" → [A]
Push "B" → [A, B]
Push "C" → [A, B, C]
Pop → [A, B] (removed "C")
Pop → [A] (removed "B")
Twee operaties definiëren een stack:
Beide zijn O(1) - instant, ongeacht de grootte van de stack.
Wanneer je een "stack overflow"-fout ziet, betekent dat letterlijk dat de call stack geen ruimte meer heeft - meestal omdat een functie zichzelf blijft aanroepen zonder te stoppen (oneindige recursie). De bekende ontwikkelaarssite Stack Overflow is naar precies deze fout vernoemd.
Je implementeert een 'ongedaan maken'-functie voor een tekentoepassing. Welke datastructuur modelleert de actiegeschiedenis het beste?
Een queue werkt als een wachtrij in een winkel: wie het eerst komt, wordt het eerst geholpen. Items worden achteraan toegevoegd en vooraan verwijderd.
Enqueue "A" → [A]
Enqueue "B" → [A, B]
Enqueue "C" → [A, B, C]
Dequeue → [B, C] (removed "A")
Dequeue → [C] (removed "B")
Een AI-API ontvangt 10.000 verzoeken per seconde. Welke structuur zorgt ervoor dat verzoeken op volgorde van aankomst worden verwerkt?
Er is ook een priority queue, waarbij items worden verwerkt op basis van prioriteit in plaats van aankomstvolgorde. AI-systemen gebruiken priority queues om urgente taken voorrang te geven - een zelfrijdende auto geeft bijvoorbeeld voorrang aan obstakeldetectie boven routeplanning.
Taalmodellen verwerken tekst als reeksen. Onder de motorkap gebruiken frameworks als PyTorch en TensorFlow linked-list-achtige structuren om berekeningsgrafen op te bouwen - ketens van bewerkingen waarbij elke stap naar de volgende wijst.
Bij het trainen van een neuraal netwerk wordt continu geheugen gealloceerd en vrijgegeven terwijl tensors worden aangemaakt en vernietigd. Geheugentoewijzers gebruiken vaak linked lists van vrije geheugenblokken om geschikte ruimte te vinden voor nieuwe tensors.
Een chatbot moet de laatste 10 berichten in een gesprek onthouden maar oudere berichten weggooien. Zou je een stack, een queue, of iets anders gebruiken? Wat gebeurt er als het 11e bericht binnenkomt?
Welke bewering over linked lists is ONWAAR?
De ongedaan-maken-geschiedenis in de meeste toepassingen heeft een limiet - meestal 100 tot 1.000 acties. Zonder deze limiet zou de stack steeds meer geheugen verbruiken. Sommige geavanceerde systemen gebruiken een combinatie van stack en queue (een "deque") om de meest recente acties te bewaren terwijl de oudste worden weggegooid.