Linked list adalah daftar yang isinya disimpan di kotak-kotak terpisah bernama node. Tiap node menyimpan dua hal: nilainya, dan alamat node berikutnya. Mirip permainan cari harta karun: tiap kertas petunjuk memberi tahu di mana kertas berikutnya, jadi kamu harus mengikutinya satu per satu dari kertas pertama.
🧪 Tebakan cepat: list-nya
10 -> 20 -> 30. Kamu mau menambah 5 di paling depan. Berapa node yang harus digeser? Tebak dulu, jawabannya ada di bagian "prepend: tambah di depan".
Node: nilai dan alamat berikutnya
Bayangkan dulu gambarnya, baru kodenya:
head
|
[10 | next] --> [20 | next] --> [30 | next] --> null
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
const a = new Node(10);
const b = new Node(20);
const c = new Node(30);
a.next = b;
b.next = c;
const head = a;
console.log(head.value); // 10
console.log(head.next.value); // 20
console.log(head.next.next.value); // 30
console.log(c.next); // null
class Nodeadalah cetakan object.new Node(10)bikin object{ value: 10, next: null }. Di dalam class,thisberarti object yang sedang dibuat.valueadalah nilainya.nextadalah node berikutnya, mulai darinull(belum ada yang berikutnya).a.next = bmenyambungakeb. Yang disimpan bukan salinanb, tapi alamat nodebitu sendiri. Penunjuk alamat ini disebut pointer atau referensi.headmenunjuk node pertama. Dari situ, semua node dicapai dengan mengikutinext:head.next.nextadalah node 30.nextdi node terakhir adalahnull. Itu tanda list-nya sudah habis.
Class LinkedList
class LinkedList {
constructor() {
this.head = null;
this.size = 0;
}
prepend(value) {
const node = new Node(value);
node.next = this.head;
this.head = node;
this.size++;
}
append(value) {
const node = new Node(value);
if (this.head === null) {
this.head = node;
} else {
let current = this.head;
while (current.next !== null) {
current = current.next;
}
current.next = node;
}
this.size++;
}
print() {
let teks = "head";
let current = this.head;
while (current !== null) {
teks += " -> " + current.value;
current = current.next;
}
return teks + " -> null";
}
}
const list = new LinkedList();
list.append(10);
list.append(20);
list.append(30);
list.prepend(5);
console.log(list.print()); // head -> 5 -> 10 -> 20 -> 30 -> null
console.log(list.size); // 4
List kosong punya head bernilai null dan size 0. Tiap kali node ditambah, di depan atau di belakang, size naik satu. Class Node dari bagian sebelumnya tetap dipakai.
prepend: tambah di depan
list.prepend(5) ke list 10 -> 20 -> 30:
| Langkah | Kode | Keadaannya |
|---|---|---|
| 1 | const node = new Node(5) |
node 5 sendirian, next-nya null |
| 2 | node.next = this.head |
5 menunjuk ke 10, list lama tergantung di belakangnya |
| 3 | this.head = node |
head -> 5 -> 10 -> 20 -> 30 -> null |
Gak ada node yang digeser, cuma dua pointer yang diubah. Itu jawaban tebakan tadi: nol. Jadi prepend selalu satu langkah, sepanjang apa pun list-nya. Itu yang disebut O(1).
Urutan langkah 2 dan 3 penting. Kalau head diganti duluan, alamat node 10 hilang dan sisa list-nya ikut hilang.
append: tambah di belakang
List cuma tahu head, jadi buat menambah di belakang, kita jalan dulu sampai node terakhir. list.append(40) ke list 10 -> 20 -> 30:
| Langkah | current di |
current.next |
Lalu |
|---|---|---|---|
| 1 | 10 | 20 | belum null, maju |
| 2 | 20 | 30 | belum null, maju |
| 3 | 30 | null |
berhenti, current.next = node |
Hasilnya 10 -> 20 -> 30 -> 40 -> null. Kalau list-nya masih kosong, node baru langsung jadi head. Makin panjang list, makin jauh jalannya: list dua kali lebih panjang, jalannya kira-kira dua kali lebih lama. Itu O(n), dengan n jumlah node.
Berjalan dari head sampai null
Semua yang perlu membaca seluruh list memakai pola yang sama, seperti print() di atas:
- Mulai dari
let current = this.head. - Selama
current !== null, pakaicurrent.value, lalu maju dengancurrent = current.next. - Begitu
currentjadinull, list-nya habis dan loop berhenti.
Mau semua nilai dalam array? Polanya sama, cuma isinya diganti: siapkan [], lalu push(current.value) tiap putaran, dan kembalikan array-nya sesudah loop.
Linked list atau array?
| Array | Linked list | |
|---|---|---|
| Ambil isi ke-i | langsung, O(1) | jalan dari head, O(n) |
| Tambah di depan | semua isi digeser, O(n) | ubah dua pointer, O(1) |
| Tambah di belakang | O(1) | O(n), kecuali punya tail |
Keunggulan utama linked list: menambah dan menghapus di depan cuma mengubah pointer, tanpa menggeser isi lain. Kelemahannya: gak bisa langsung loncat ke isi ke-i.
⚠️ Jebakan yang sering ketemu
- Urutan di
prependterbalik.this.head = nodelalunode.next = this.headbikin node baru menunjuk dirinya sendiri. Sambungkannode.nextdulu, baru gantihead. - Lupa
current = current.next.currentgak pernah maju, jadi loop-nya gak pernah berhenti dan halamannya macet. - Menempel di
headwaktu append.this.head.next = nodemenimpa sambungan ke node kedua, sisanya hilang. Jalan dulu sampai node yangnext-nyanull. - Lupa
this.size++. Node-nya masuk, tapi jumlahnya tetap 0.
💡 Pointer
tail. Kalau list juga menyimpantail, alamat node terakhir, append gak perlu jalan lagi: langsungthis.tail.next = node, laluthis.tail = node. Append jadi O(1). Tapi menghapus node terakhir tetap harus jalan darihead, karenanextcuma mengarah ke depan.
TL;DR: Linked list adalah rangkaian node. Tiap node menyimpan value dan next, alamat node berikutnya, dan node terakhir next-nya null. head menunjuk node pertama. prepend bikin node baru, node.next = this.head, lalu this.head = node: O(1), tanpa menggeser apa pun. append jalan dari head sampai node yang next-nya null, lalu menyambung di situ: O(n). Membaca seluruh list: current mulai dari head, maju lewat current.next sampai null. Jangan lupa size++ di tiap penambahan.