1. Geschiedenis vanLinkedList
Java heeft een andere verzamelklasse die Java heeft geërfd van de C++-taal. Dit is de LinkedList
klasse die een "gekoppelde lijst" implementeert.
Uiterlijk LinkedList
lijkt een hetzelfde te zijn als een ArrayList
. De LinkedList
klasse heeft allemaal dezelfde methoden als de ArrayList
klasse. In principe kun je altijd een gebruiken LinkedList
in plaats van een ArrayList
en dan werkt alles.
Dus waarom hebben we nog een lijstklasse nodig?
Het antwoord heeft alles te maken met de interne structuur van de LinkedList
klas. In plaats van een array gebruikt het een dubbel gekoppelde lijst . Wat dat is, leggen we later uit.
De LinkedList
verschillende interne structuur van de klasse maakt het het snelst in het invoegen van elementen in het midden van de lijst.
Op internet kun je vaak vergelijkingen vinden van de klassen ArrayList
en LinkedList
:
Operatie | Methode | ArrayLijst | Gelinkte lijst |
---|---|---|---|
Voeg een onderdeel toe |
|
Snel | Erg snel |
Voeg een element in |
|
Langzaam | Erg snel |
Krijg een element |
|
Erg snel | Langzaam |
Stel een onderdeel in |
|
Erg snel | Langzaam |
Verwijder een onderdeel |
|
Langzaam | Erg snel |
Alles lijkt duidelijk genoeg: als je vaak elementen in de lijst moet invoegen, gebruik dan LinkedList
; indien zelden, gebruik dan ArrayList. Maar de realiteit is een beetje anders.
2. Niemand gebruiktLinkedList
Niemand gebruikt LinkedList
.
Zelfs de auteur van de LinkedList
klas tweette onlangs: "Gebruikt iemand het eigenlijk LinkedList
? Ik heb het geschreven en ik gebruik het nooit."
Dus wat is de deal?
Ten eerste begon de klas heel snel elementen in het midden van de lijst in te voegen. ArrayList
Wanneer u een element in het midden van de lijst invoegt, moet u alle elementen na het invoegpunt met 1 naar het einde van de lijst verschuiven. Vroeger kostte dit tijd.
Maar nu is alles veranderd. Alle elementen van een array bevinden zich dicht bij elkaar in hetzelfde geheugenblok, dus de bewerking om de elementen te verschuiven wordt uitgevoerd door een zeer snel commando op laag niveau: .System.arraycopy()
Bovendien hebben de huidige processors een grote cache die meestal de hele array kan bevatten, waardoor de array-elementen in de cache kunnen worden verplaatst in plaats van in het geheugen. Een miljoen elementen worden gemakkelijk verschoven in een enkele milliseconde.
Ten tweede kan de LinkedList
klasse snel elementen invoegen als je ze invoegt met een iterator. Als je een iterator gebruikt om door a te gaan LinkedList
en constant nieuwe elementen invoegt (of bestaande verwijdert), is de operatie supersnel.
Als u eenvoudigweg elementen toevoegt aan een LinkedList
object binnen een lus, gaat elke snelle invoegbewerking gepaard met een langzame "get element"-bewerking.
De realiteit komt hier veel dichter bij:
Operatie | Methode | ArrayLijst | Gelinkte lijst |
---|---|---|---|
Voeg een onderdeel toe |
|
Snel | Erg snel |
Voeg een element in |
|
Langzaam | Zeer langzaam |
Krijg een element |
|
Erg snel | Zeer langzaam |
Stel een onderdeel in |
|
Erg snel | Zeer langzaam |
Verwijder een onderdeel |
|
Langzaam | Zeer langzaam |
Invoegen met behulp van een iterator |
|
Langzaam | Erg snel |
Verwijderen met behulp van een iterator |
|
Langzaam | Erg snel |
Waarom is het verkrijgen van een element uit zo'n LinkedList
trage operatie?
U kunt die vraag beantwoorden nadat u een beetje vertrouwd bent geraakt met hoe LinkedList
het is gestructureerd.
3. Hoe LinkedList
is gestructureerd
LinkedList
heeft een andere interne structuur dan ArrayList
. Het heeft geen interne array voor het opslaan van elementen. In plaats daarvan gebruikt het een gegevensstructuur die een dubbel geïnkte lijst wordt genoemd .
Elk element van een dubbel gelinkte lijst slaat een verwijzing op naar het vorige element en het volgende element. Dit lijkt een beetje op een rij in een winkel, waar elke persoon zich zowel de persoon die voor hem staat als de persoon die achter hem staat herinnert.
Zo ziet zo'n lijst er in het geheugen uit:
De kop en staart (cellen met een grijze achtergrond) zijn de first
en last
variabelen, die verwijzingen naar Node
objecten opslaan.
In het midden heb je een keten van Node
objecten (objecten, geen variabelen). Elk van hen bestaat uit drie velden:
prev
— slaat een verwijzing (link) op naar het vorigeNode
object (cellen met een gele achtergrond).value
— slaat de waarde op van dit element van de lijst (cellen met een groene achtergrond).next
— slaat een verwijzing (link) op naar het volgendeNode
object (cellen met een blauwe achtergrond)
Het tweede object (adres F24) is het volgende ( next
) voor het eerste object en het vorige ( prev
) voor het derde object. Het gele veld van het derde object bevat het adres F24 en het blauwe veld van het eerste object bevat het adres F24.
De pijlen van het eerste en derde object wijzen naar hetzelfde tweede object. Het zou dus juister zijn om de pijlen zo te tekenen.
4. Voeg een element toe aan een gekoppelde lijst
Om iemand op deze manier aan de lijn toe te voegen, heb je alleen toestemming nodig van twee mensen die naast elkaar staan. De eerste persoon herinnert zich de nieuwkomer als "de persoon achter mij", en de tweede persoon herinnert zich hen als "de persoon voor mij".
Het enige dat u hoeft te doen, is de referenties van de twee aangrenzende objecten wijzigen:
We hebben een nieuw item aan onze lijst toegevoegd door de referenties van het tweede en derde object te wijzigen. Het nieuwe object is het volgende voor het oude tweede object en het vorige voor het oude derde object. En natuurlijk moet het nieuwe object zelf de juiste referenties opslaan: het vorige object is het oude tweede object en het volgende object is het oude derde object.
Het verwijderen van een element is nog eenvoudiger: als we bijvoorbeeld het 100e object uit de lijst willen verwijderen, hoeven we alleen het veld voor het 99e object te wijzigen next
zodat het naar het 101e object verwijst, en het prev
veld voor het 101e object te wijzigen object zodat het naar de 99e wijst. Dat is het.
Maar het 100ste object krijgen is niet zo eenvoudig.
5. Verwijder een element uit een lijst
Om het 100ste element van een gelinkte lijst te krijgen, moet u:
Haal het 1e object op: Dit doe je met behulp van de first
variabele in het LinkedList
object. Het next
veld van het 1e object bevat een verwijzing naar het 2e object. Zo krijgen we het tweede object. Het 2e object heeft een verwijzing naar het derde, enzovoort.
Als we een verwijzing naar het 100e object nodig hebben, moeten we achtereenvolgens door alle objecten van het 1e tot het 100e gaan. En als we het miljoenste element in een lijst nodig hebben, moeten we meer dan een miljoen objecten achter elkaar herhalen!
En als deze objecten op verschillende tijdstippen aan de lijst zijn toegevoegd, bevinden ze zich in verschillende delen van het geheugen en zullen ze waarschijnlijk niet tegelijkertijd in de cache van de processor terechtkomen. Dit betekent dat het herhalen van de elementen van een gelinkte lijst niet alleen traag is, maar ook erg traag.
Dat is waar we mee te maken hebben.
Dus waarom leren we je hoe deze slow LinkedList
werkt?
Welnu, tijdens sollicitatiegesprekken wordt u gevraagd hoe LinkedList
verschilt vanArrayList
. Zeker.
GO TO FULL VERSION