LinkedList în Java

Listă dublu înlănțuită: adăugare și ștergere rapide la ambele capete; implementează și List, și Deque.

Sintaxă
new LinkedList<>()
new LinkedList<>(Collection<? extends E> c)

void addFirst(E e)
void addLast(E e)
E getFirst()
E removeFirst()

Ce face LinkedList

LinkedList ține fiecare element într-un „nod” care știe de nodul dinainte și de cel de după. Adăugarea și ștergerea la capete (addFirst, addLast, removeFirst) sunt rapide, pentru că doar se leagă noduri noi. În schimb, get(i) trebuie să meargă nod cu nod până la poziția i, deci este lent pe liste mari.

Clasa implementează atât List, cât și Deque, deci o poți folosi ca listă, ca stivă sau ca coadă. addFirst pune elementul la început, addLast la sfârșit, getFirst citește primul element fără să-l scoată, iar removeFirst îl scoate și îl returnează.

Pe o listă goală, getFirst și removeFirst aruncă NoSuchElementException. În practică, ArrayList (pentru liste) și ArrayDeque (pentru cozi și stive) sunt de obicei mai rapide; LinkedList rămâne utilă când vrei o singură structură care să fie și listă, și coadă.

Parametri

Parametru Descriere
e Elementul de adăugat (pentru addFirst / addLast).
c Colecția din care se copiază elementele inițiale.

Ce returnează

addFirst și addLast: nimic. getFirst: primul element. removeFirst: primul element, care a fost scos din listă.

Exemple

Exemplul 1: Adăugare la ambele capete

import java.util.LinkedList;

public class Main {
    public static void main(String[] args) {
        LinkedList<String> tren = new LinkedList<>();
        tren.addLast("vagon 1");
        tren.addLast("vagon 2");
        tren.addFirst("locomotivă");
        tren.addLast("vagon de marfă");

        System.out.println(tren);
        System.out.println("În față: " + tren.getFirst());
    }
}

Rezultat

[locomotivă, vagon 1, vagon 2, vagon de marfă]
În față: locomotivă

Exemplul 2: Rând de așteptare la ghișeu

Clienții noi intră la sfârșit cu addLast; cel din față este servit și scos cu removeFirst.

import java.util.LinkedList;

public class Main {
    public static void main(String[] args) {
        LinkedList<String> rand = new LinkedList<>();
        rand.addLast("Ana");
        rand.addLast("Bogdan");
        rand.addLast("Carmen");

        while (!rand.isEmpty()) {
            String client = rand.removeFirst();
            System.out.println("Este servit(ă): " + client + ", mai așteaptă " + rand.size());
        }
    }
}

Rezultat

Este servit(ă): Ana, mai așteaptă 2
Este servit(ă): Bogdan, mai așteaptă 1
Este servit(ă): Carmen, mai așteaptă 0

Exemplul 3: getFirst pe o listă goală

Excepția NoSuchElementException este prinsă cu try/catch. Verifică isEmpty() înainte, sau folosește peekFirst(), care returnează null.

import java.util.LinkedList;
import java.util.NoSuchElementException;

public class Main {
    public static void main(String[] args) {
        LinkedList<Integer> numere = new LinkedList<>();
        try {
            System.out.println(numere.getFirst());
        } catch (NoSuchElementException e) {
            System.out.println("Lista este goală: " + e.getClass().getSimpleName());
        }
        System.out.println("peekFirst: " + numere.peekFirst());
    }
}

Rezultat

Lista este goală: NoSuchElementException
peekFirst: null

Greșeli frecvente

  • Parcurgi un LinkedList mare cu for (int i = 0; i < l.size(); i++) l.get(i). Fiecare get pornește de la capăt, deci bucla devine foarte lentă; folosește for-each sau un iterator.
  • Alegi LinkedList „pentru că inserarea e rapidă”. Inserarea la mijloc trebuie întâi să ajungă la poziție, nod cu nod; de obicei ArrayList este la fel de rapid sau mai rapid.
  • Apelezi removeFirst() fără să verifici dacă lista e goală și programul se oprește cu NoSuchElementException.

Comenzi înrudite

  • ArrayList: Lista implementată cu un array intern care crește automat; acces foarte rapid după index. Cea mai folosită listă din Java.
  • List: Interfața pentru liste ordonate: elementele au poziții (0, 1, 2…), se pot repeta și se pot citi după index.
  • Deque: Coadă cu două capete: adaugi și scoți atât la început, cât și la sfârșit. Se folosește și ca stivă, și ca coadă.
  • ArrayDeque: Implementarea recomandată pentru cozi și stive: un array circular care crește automat, rapid la ambele capete.
  • List.addFirst: Adaugă un element la începutul (addFirst) sau la sfârșitul (addLast) listei; metode noi din Java 21.
  • Deque.pollFirst: pollFirst și pollLast scot primul sau ultimul element dintr-un Deque; peekFirst și peekLast doar îl arată. Pe gol dau null.