- Pengenalan Linked List
- Single Linked List
- Double Linked List
- Circular Linked List
- Perbandingan dan Kompleksitas
- Latihan Praktikum
Linked List adalah struktur data linear yang terdiri dari kumpulan node yang saling terhubung melalui pointer/referensi. Berbeda dengan array yang menyimpan data secara kontinu di memori, linked list menyimpan data secara tersebar dan dihubungkan dengan pointer.
Setiap node dalam linked list minimal memiliki:
| Komponen | Deskripsi |
|---|---|
| Data | Nilai/informasi yang disimpan |
| Pointer (Next) | Referensi ke node berikutnya |
| Pointer (Prev) | Referensi ke node sebelumnya (khusus Double Linked List) |
| Jenis | Karakteristik | Traversal |
|---|---|---|
| Single Linked List | Setiap node punya 1 pointer (next) | Satu arah (maju) |
| Double Linked List | Setiap node punya 2 pointer (prev, next) | Dua arah (maju & mundur) |
| Circular Single | Node terakhir menunjuk ke node pertama | Satu arah, melingkar |
| Circular Double | Kombinasi double dan circular | Dua arah, melingkar |
Keuntungan:
- Ukuran dinamis (tidak perlu deklarasi ukuran di awal)
- Insert dan delete di awal/tengah lebih efisien daripada array
- Tidak ada pemborosan memori (alokasi sesuai kebutuhan)
Kekurangan:
- Tidak mendukung akses random (harus traverse dari awal)
- Membutuhkan memori ekstra untuk pointer
- Cache performance kurang optimal
Single Linked List terdiri dari node-node yang masing-masing memiliki data dan pointer next yang menunjuk ke node berikutnya. Node terakhir menunjuk ke null.
[HEAD] -> [Data|Next] -> [Data|Next] -> [Data|Next] -> NULL
class Node {
int data; // Data yang disimpan
Node next; // Pointer ke node berikutnya
// Constructor
public Node(int data) {
this.data = data;
this.next = null;
}
}class SingleLinkedList {
private Node head; // Pointer ke node pertama
private int size; // Jumlah node dalam list
// Constructor
public SingleLinkedList() {
this.head = null;
this.size = 0;
}
// Method isEmpty untuk cek list kosong
public boolean isEmpty() {
return head == null;
}
// Method getSize untuk mendapatkan jumlah node
public int getSize() {
return size;
}
}Berikut adalah operasi-operasi yang dapat dilakukan pada Single Linked List:
| Operasi | Fungsi | Kompleksitas |
|---|---|---|
insertAtBeginning(data) |
Menambah node di awal list | O(1) |
insertAtEnd(data) |
Menambah node di akhir list | O(n) |
insertAtPosition(data, pos) |
Menambah node di posisi tertentu | O(n) |
deleteAtBeginning() |
Menghapus node di awal list | O(1) |
deleteAtEnd() |
Menghapus node di akhir list | O(n) |
deleteByValue(value) |
Menghapus node berdasarkan nilai | O(n) |
search(value) |
Mencari posisi node dengan nilai tertentu | O(n) |
get(position) |
Mengambil data pada posisi tertentu | O(n) |
update(position, data) |
Mengubah data pada posisi tertentu | O(n) |
display() |
Menampilkan seluruh isi list | O(n) |
reverse() |
Membalik urutan list | O(n) |
Menambahkan node baru di posisi paling depan list.
Langkah-langkah:
- Buat node baru
- Arahkan
nextnode baru keheadsaat ini - Update
headmenjadi node baru
public void insertAtBeginning(int data) {
// 1. Buat node baru
Node newNode = new Node(data);
// 2. Arahkan `next` node baru ke `head` saat ini
newNode.next = head;
// 3. Update `head` menjadi node baru
head = newNode;
size++;
}Contoh penggunaan:
SingleLinkedList list = new SingleLinkedList();
list.insertAtBeginning(10); // List: 10 -> NULL
list.insertAtBeginning(20); // List: 20 -> 10 -> NULL
list.insertAtBeginning(30); // List: 30 -> 20 -> 10 -> NULLMenambahkan node baru di posisi paling belakang list.
Langkah-langkah:
- Buat node baru
- Jika list kosong, jadikan node baru sebagai head
- Jika tidak, traverse sampai node terakhir
- Arahkan
nextnode terakhir ke node baru
public void insertAtEnd(int data) {
// 1. Buat node baru
Node newNode = new Node(data);
// 2. Jika list kosong, jadikan node baru sebagai head
if (head == null) {
head = newNode;
size++;
return;
}
// 3. Traverse sampai node terakhir
Node current = head;
while (current.next != null) {
current = current.next;
}
// 4. Arahkan next node terakhir ke node baru
current.next = newNode;
size++;
}Contoh penggunaan:
SingleLinkedList list = new SingleLinkedList();
list.insertAtEnd(10); // List: 10 -> NULL
list.insertAtEnd(20); // List: 10 -> 20 -> NULL
list.insertAtEnd(30); // List: 10 -> 20 -> 30 -> NULLMenambahkan node baru pada posisi yang ditentukan (0-indexed).
Langkah-langkah:
- Validasi posisi (0 <= pos <= size)
- Jika posisi 0, panggil insertAtBeginning
- Traverse sampai node sebelum posisi target
- Sisipkan node baru
public void insertAtPosition(int data, int position) {
// 1. Validasi posisi
if (position < 0 || position > size) {
System.out.println("Posisi tidak valid!");
return;
}
// 2. Jika posisi 0, insert di awal
if (position == 0) {
insertAtBeginning(data);
return;
}
// 3. Buat node baru
Node newNode = new Node(data);
// 4. Traverse sampai node sebelum posisi target
Node current = head;
for (int i = 0; i < position - 1; i++) {
current = current.next;
}
// 5. Sisipkan node baru
newNode.next = current.next;
current.next = newNode;
size++;
}Contoh penggunaan:
// List awal: 10 -> 20 -> 30 -> NULL
list.insertAtPosition(25, 2);
// List akhir: 10 -> 20 -> 25 -> 30 -> NULLMenghapus node di posisi paling depan list.
Langkah-langkah:
- Cek apakah list kosong
- Simpan data node yang akan dihapus (opsional)
- Update head ke node berikutnya
public int deleteAtBeginning() {
// 1. Cek apakah list kosong
if (isEmpty()) {
System.out.println("List kosong!");
return -1;
}
// 2. Simpan data node yang akan dihapus
int deletedData = head.data;
// 3. Update head ke node berikutnya
head = head.next;
size--;
return deletedData;
}Contoh penggunaan:
// List awal: 30 -> 20 -> 10 -> NULL
int deleted = list.deleteAtBeginning(); // deleted = 30
// List akhir: 20 -> 10 -> NULLMenghapus node di posisi paling belakang list.
Langkah-langkah:
- Cek apakah list kosong
- Jika hanya ada 1 node, hapus head
- Traverse sampai node sebelum node terakhir
- Set
nextnode tersebut menjadi null
public int deleteAtEnd() {
// 1. Cek apakah list kosong
if (isEmpty()) {
System.out.println("List kosong!");
return -1;
}
// 2. Jika hanya ada 1 node
if (head.next == null) {
int deletedData = head.data;
head = null;
size--;
return deletedData;
}
// 3. Traverse sampai node sebelum node terakhir
Node current = head;
while (current.next.next != null) {
current = current.next;
}
// 4. Simpan data dan hapus node terakhir
int deletedData = current.next.data;
current.next = null;
size--;
return deletedData;
}Contoh penggunaan:
// List awal: 10 -> 20 -> 30 -> NULL
int deleted = list.deleteAtEnd(); // deleted = 30
// List akhir: 10 -> 20 -> NULLMenghapus node pertama yang memiliki nilai tertentu.
Langkah-langkah:
- Cek apakah list kosong
- Jika nilai ada di head, hapus head
- Traverse untuk mencari node dengan nilai tersebut
- Jika ditemukan, update pointer untuk melewati node tersebut
Gambar 2.7 Proses Delete Berdasarkan Nilai
public boolean deleteByValue(int value) {
// 1. Cek apakah list kosong
if (isEmpty()) {
System.out.println("List kosong!");
return false;
}
// 2. Jika nilai ada di head
if (head.data == value) {
head = head.next;
size--;
return true;
}
// 3. Traverse untuk mencari node dengan nilai tersebut
Node current = head;
while (current.next != null && current.next.data != value) {
current = current.next;
}
// 4. Jika tidak ditemukan
if (current.next == null) {
System.out.println("Nilai " + value + " tidak ditemukan!");
return false;
}
// 5. Hapus node dengan mengupdate pointer
current.next = current.next.next;
size--;
return true;
}Contoh penggunaan:
// List awal: 10 -> 20 -> 30 -> 40 -> NULL
list.deleteByValue(30);
// List akhir: 10 -> 20 -> 40 -> NULLMencari posisi node dengan nilai tertentu.
public int search(int value) {
Node current = head;
int position = 0;
while (current != null) {
if (current.data == value) {
return position; // Ditemukan, return posisi
}
current = current.next;
position++;
}
return -1; // Tidak ditemukan
}Contoh penggunaan:
// List: 10 -> 20 -> 30 -> NULL
int pos = list.search(20); // pos = 1
int pos2 = list.search(50); // pos2 = -1 (tidak ditemukan)Mengambil data pada posisi tertentu.
public int get(int position) {
// Validasi posisi
if (position < 0 || position >= size) {
throw new IndexOutOfBoundsException("Posisi tidak valid!");
}
// Traverse ke posisi yang diminta
Node current = head;
for (int i = 0; i < position; i++) {
current = current.next;
}
return current.data;
}Contoh penggunaan:
// List: 10 -> 20 -> 30 -> NULL
int data = list.get(1); // data = 20Mengubah data pada posisi tertentu.
public void update(int position, int newData) {
// Validasi posisi
if (position < 0 || position >= size) {
System.out.println("Posisi tidak valid!");
return;
}
// Traverse ke posisi yang diminta
Node current = head;
for (int i = 0; i < position; i++) {
current = current.next;
}
// Update data
current.data = newData;
}Contoh penggunaan:
// List awal: 10 -> 20 -> 30 -> NULL
list.update(1, 25);
// List akhir: 10 -> 25 -> 30 -> NULLMenampilkan seluruh isi list.
public void display() {
if (isEmpty()) {
System.out.println("List kosong!");
return;
}
System.out.print("List: ");
Node current = head;
while (current != null) {
System.out.print(current.data);
if (current.next != null) {
System.out.print(" -> ");
}
current = current.next;
}
System.out.println(" -> NULL");
System.out.println("Size: " + size);
}Output contoh:
List: 10 -> 20 -> 30 -> NULL
Size: 3
Membalik urutan list.
Langkah-langkah:
- Inisialisasi 3 pointer: prev, current, next
- Traverse list sambil membalik arah pointer
- Update head ke node terakhir (prev)
public void reverse() {
Node prev = null;
Node current = head;
Node next = null;
while (current != null) {
// Simpan next node
next = current.next;
// Balik arah pointer
current.next = prev;
// Geser prev dan current
prev = current;
current = next;
}
// Update head ke node terakhir
head = prev;
}Contoh penggunaan:
// List awal: 10 -> 20 -> 30 -> NULL
list.reverse();
// List akhir: 30 -> 20 -> 10 -> NULLBerikut adalah implementasi lengkap Single Linked List dengan semua operasi:
public class Node {
int data;
Node next;
public Node(int data) {
this.data = data;
this.next = null;
}
}public class SingleLinkedList {
private Node head;
private int size;
public SingleLinkedList() {
this.head = null;
this.size = 0;
}
public boolean isEmpty() {
return head == null;
}
public int getSize() {
return size;
}
// ========== INSERT OPERATIONS ==========
public void insertAtBeginning(int data) {
Node newNode = new Node(data);
newNode.next = head;
head = newNode;
size++;
}
public void insertAtEnd(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
} else {
Node current = head;
while (current.next != null) {
current = current.next;
}
current.next = newNode;
}
size++;
}
public void insertAtPosition(int data, int position) {
if (position < 0 || position > size) {
System.out.println("Posisi tidak valid!");
return;
}
if (position == 0) {
insertAtBeginning(data);
return;
}
Node newNode = new Node(data);
Node current = head;
for (int i = 0; i < position - 1; i++) {
current = current.next;
}
newNode.next = current.next;
current.next = newNode;
size++;
}
// ========== DELETE OPERATIONS ==========
public int deleteAtBeginning() {
if (isEmpty()) {
System.out.println("List kosong!");
return -1;
}
int deletedData = head.data;
head = head.next;
size--;
return deletedData;
}
public int deleteAtEnd() {
if (isEmpty()) {
System.out.println("List kosong!");
return -1;
}
if (head.next == null) {
int deletedData = head.data;
head = null;
size--;
return deletedData;
}
Node current = head;
while (current.next.next != null) {
current = current.next;
}
int deletedData = current.next.data;
current.next = null;
size--;
return deletedData;
}
public boolean deleteByValue(int value) {
if (isEmpty()) {
return false;
}
if (head.data == value) {
head = head.next;
size--;
return true;
}
Node current = head;
while (current.next != null && current.next.data != value) {
current = current.next;
}
if (current.next == null) {
return false;
}
current.next = current.next.next;
size--;
return true;
}
// ========== OTHER OPERATIONS ==========
public int search(int value) {
Node current = head;
int position = 0;
while (current != null) {
if (current.data == value) {
return position;
}
current = current.next;
position++;
}
return -1;
}
public int get(int position) {
if (position < 0 || position >= size) {
throw new IndexOutOfBoundsException("Posisi tidak valid!");
}
Node current = head;
for (int i = 0; i < position; i++) {
current = current.next;
}
return current.data;
}
public void update(int position, int newData) {
if (position < 0 || position >= size) {
System.out.println("Posisi tidak valid!");
return;
}
Node current = head;
for (int i = 0; i < position; i++) {
current = current.next;
}
current.data = newData;
}
public void reverse() {
Node prev = null;
Node current = head;
Node next = null;
while (current != null) {
next = current.next;
current.next = prev;
prev = current;
current = next;
}
head = prev;
}
public void display() {
if (isEmpty()) {
System.out.println("List kosong!");
return;
}
System.out.print("List: ");
Node current = head;
while (current != null) {
System.out.print(current.data);
if (current.next != null) {
System.out.print(" -> ");
}
current = current.next;
}
System.out.println(" -> NULL");
}
public void clear() {
head = null;
size = 0;
}
}public class Main {
public static void main(String[] args) {
SingleLinkedList list = new SingleLinkedList();
System.out.println("=== INSERT OPERATIONS ===");
list.insertAtBeginning(10);
list.insertAtBeginning(20);
list.insertAtEnd(5);
list.insertAtEnd(15);
list.display();
// Output: List: 20 -> 10 -> 5 -> 15 -> NULL
list.insertAtPosition(25, 2);
list.display();
// Output: List: 20 -> 10 -> 25 -> 5 -> 15 -> NULL
System.out.println("\n=== SEARCH & GET ===");
System.out.println("Posisi nilai 25: " + list.search(25));
System.out.println("Data di posisi 2: " + list.get(2));
System.out.println("\n=== UPDATE ===");
list.update(2, 30);
list.display();
// Output: List: 20 -> 10 -> 30 -> 5 -> 15 -> NULL
System.out.println("\n=== DELETE OPERATIONS ===");
list.deleteAtBeginning();
list.display();
// Output: List: 10 -> 30 -> 5 -> 15 -> NULL
list.deleteAtEnd();
list.display();
// Output: List: 10 -> 30 -> 5 -> NULL
list.deleteByValue(30);
list.display();
// Output: List: 10 -> 5 -> NULL
System.out.println("\n=== REVERSE ===");
list.insertAtEnd(100);
list.insertAtEnd(200);
list.display();
list.reverse();
list.display();
// Output: List: 200 -> 100 -> 5 -> 10 -> NULL
}
}Double Linked List memiliki node dengan dua pointer: prev (ke node sebelumnya) dan next (ke node berikutnya). Ini memungkinkan traversal dua arah.
Gambar 3.1 Struktur Double Linked List
NULL <- [Prev|Data|Next] <-> [Prev|Data|Next] <-> [Prev|Data|Next] -> NULL
^ ^
HEAD TAIL
class DoubleNode {
int data;
DoubleNode prev; // Pointer ke node sebelumnya
DoubleNode next; // Pointer ke node berikutnya
public DoubleNode(int data) {
this.data = data;
this.prev = null;
this.next = null;
}
}class DoubleLinkedList {
private DoubleNode head; // Pointer ke node pertama
private DoubleNode tail; // Pointer ke node terakhir
private int size;
public DoubleLinkedList() {
this.head = null;
this.tail = null;
this.size = 0;
}
public boolean isEmpty() {
return head == null;
}
public int getSize() {
return size;
}
}| Operasi | Fungsi | Kompleksitas |
|---|---|---|
insertAtBeginning(data) |
Menambah node di awal | O(1) |
insertAtEnd(data) |
Menambah node di akhir | O(1)* |
deleteAtBeginning() |
Menghapus node di awal | O(1) |
deleteAtEnd() |
Menghapus node di akhir | O(1)* |
displayForward() |
Menampilkan list dari depan ke belakang | O(n) |
displayBackward() |
Menampilkan list dari belakang ke depan | O(n) |
*O(1) karena ada tail pointer
Keuntungan Double Linked List:
- Traversal bisa dua arah
- Delete node lebih mudah (tidak perlu track node sebelumnya)
- Operasi di tail menjadi O(1)
Kekurangan:
- Membutuhkan memori ekstra untuk pointer prev
- Operasi insert/delete lebih kompleks
Gambar 3.2 Proses Insert di Awal pada Double Linked List
public void insertAtBeginning(int data) {
DoubleNode newNode = new DoubleNode(data);
if (isEmpty()) {
// Jika list kosong, head dan tail sama
head = newNode;
tail = newNode;
} else {
// Hubungkan node baru dengan head lama
newNode.next = head;
head.prev = newNode;
head = newNode;
}
size++;
}
Gambar 3.3 Proses Insert di Akhir pada Double Linked List
public void insertAtEnd(int data) {
DoubleNode newNode = new DoubleNode(data);
if (isEmpty()) {
head = newNode;
tail = newNode;
} else {
// Hubungkan node baru dengan tail lama
newNode.prev = tail;
tail.next = newNode;
tail = newNode;
}
size++;
}
Gambar 3.4 Proses Delete di Awal pada Double Linked List
public int deleteAtBeginning() {
if (isEmpty()) {
System.out.println("List kosong!");
return -1;
}
int deletedData = head.data;
if (head == tail) {
// Hanya ada 1 node
head = null;
tail = null;
} else {
head = head.next;
head.prev = null;
}
size--;
return deletedData;
}
Gambar 3.5 Proses Delete di Akhir pada Double Linked List
public int deleteAtEnd() {
if (isEmpty()) {
System.out.println("List kosong!");
return -1;
}
int deletedData = tail.data;
if (head == tail) {
// Hanya ada 1 node
head = null;
tail = null;
} else {
tail = tail.prev;
tail.next = null;
}
size--;
return deletedData;
}// Menampilkan dari depan ke belakang
public void displayForward() {
if (isEmpty()) {
System.out.println("List kosong!");
return;
}
System.out.print("Forward: NULL <- ");
DoubleNode current = head;
while (current != null) {
System.out.print(current.data);
if (current.next != null) {
System.out.print(" <-> ");
}
current = current.next;
}
System.out.println(" -> NULL");
}
// Menampilkan dari belakang ke depan
public void displayBackward() {
if (isEmpty()) {
System.out.println("List kosong!");
return;
}
System.out.print("Backward: NULL <- ");
DoubleNode current = tail;
while (current != null) {
System.out.print(current.data);
if (current.prev != null) {
System.out.print(" <-> ");
}
current = current.prev;
}
System.out.println(" -> NULL");
}public class DoubleNode {
int data;
DoubleNode prev;
DoubleNode next;
public DoubleNode(int data) {
this.data = data;
this.prev = null;
this.next = null;
}
}public class DoubleLinkedList {
private DoubleNode head;
private DoubleNode tail;
private int size;
public DoubleLinkedList() {
this.head = null;
this.tail = null;
this.size = 0;
}
public boolean isEmpty() {
return head == null;
}
public int getSize() {
return size;
}
// ========== INSERT OPERATIONS ==========
public void insertAtBeginning(int data) {
DoubleNode newNode = new DoubleNode(data);
if (isEmpty()) {
head = newNode;
tail = newNode;
} else {
newNode.next = head;
head.prev = newNode;
head = newNode;
}
size++;
}
public void insertAtEnd(int data) {
DoubleNode newNode = new DoubleNode(data);
if (isEmpty()) {
head = newNode;
tail = newNode;
} else {
newNode.prev = tail;
tail.next = newNode;
tail = newNode;
}
size++;
}
// ========== DELETE OPERATIONS ==========
public int deleteAtBeginning() {
if (isEmpty()) {
return -1;
}
int deletedData = head.data;
if (head == tail) {
head = null;
tail = null;
} else {
head = head.next;
head.prev = null;
}
size--;
return deletedData;
}
public int deleteAtEnd() {
if (isEmpty()) {
return -1;
}
int deletedData = tail.data;
if (head == tail) {
head = null;
tail = null;
} else {
tail = tail.prev;
tail.next = null;
}
size--;
return deletedData;
}
// ========== DISPLAY OPERATIONS ==========
public void displayForward() {
if (isEmpty()) {
System.out.println("List kosong!");
return;
}
System.out.print("Forward: NULL <- ");
DoubleNode current = head;
while (current != null) {
System.out.print(current.data);
if (current.next != null) {
System.out.print(" <-> ");
}
current = current.next;
}
System.out.println(" -> NULL");
}
public void displayBackward() {
if (isEmpty()) {
System.out.println("List kosong!");
return;
}
System.out.print("Backward: NULL <- ");
DoubleNode current = tail;
while (current != null) {
System.out.print(current.data);
if (current.prev != null) {
System.out.print(" <-> ");
}
current = current.prev;
}
System.out.println(" -> NULL");
}
}public class Main {
public static void main(String[] args) {
DoubleLinkedList list = new DoubleLinkedList();
System.out.println("=== INSERT OPERATIONS ===");
list.insertAtBeginning(10);
list.insertAtBeginning(20);
list.insertAtEnd(5);
list.insertAtEnd(15);
list.displayForward();
// Output: Forward: NULL <- 20 <-> 10 <-> 5 <-> 15 -> NULL
list.displayBackward();
// Output: Backward: NULL <- 15 <-> 5 <-> 10 <-> 20 -> NULL
System.out.println("\n=== DELETE OPERATIONS ===");
System.out.println("Deleted from beginning: " + list.deleteAtBeginning());
list.displayForward();
// Output: Forward: NULL <- 10 <-> 5 <-> 15 -> NULL
System.out.println("Deleted from end: " + list.deleteAtEnd());
list.displayForward();
// Output: Forward: NULL <- 10 <-> 5 -> NULL
}
}Pada Circular Single Linked List, node terakhir menunjuk kembali ke node pertama (head), membentuk lingkaran.
Gambar 4.1 Struktur Circular Single Linked List
+---> [Data|Next] -> [Data|Next] -> [Data|Next] ---+
| |
+---------------------------------------------------+
class CircularSingleLinkedList {
private Node head;
private Node tail;
private int size;
public void insertAtEnd(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
tail = newNode;
newNode.next = head; // Menunjuk ke diri sendiri
} else {
tail.next = newNode;
newNode.next = head; // Node baru menunjuk ke head
tail = newNode;
}
size++;
}
public void display() {
if (head == null) {
System.out.println("List kosong!");
return;
}
Node current = head;
System.out.print("Circular: ");
do {
System.out.print(current.data + " -> ");
current = current.next;
} while (current != head);
System.out.println("(kembali ke " + head.data + ")");
}
}Kombinasi Double Linked List dan Circular, dimana head.prev menunjuk ke tail, dan tail.next menunjuk ke head.
Gambar 4.2 Struktur Circular Double Linked List
+---> [Prev|Data|Next] <-> [Prev|Data|Next] <-> [Prev|Data|Next] <---+
| |
+---------------------------------------------------------------------+
class CircularDoublyLinkedList {
class Node {
int data;
Node prev, next;
Node(int data) {
this.data = data;
this.prev = this.next = null;
}
}
private Node head;
public void insertAtEnd(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
head.next = head;
head.prev = head;
} else {
Node tail = head.prev;
newNode.next = head;
newNode.prev = tail;
head.prev = newNode;
tail.next = newNode;
}
}
public void displayForward() {
if (head == null) return;
Node current = head;
System.out.print("Forward: (tail) <-> ");
do {
System.out.print(current.data + " <-> ");
current = current.next;
} while (current != head);
System.out.println("(head)");
}
}| Operasi | Single LL | Double LL | Array |
|---|---|---|---|
| Insert di awal | O(1) | O(1) | O(n) |
| Insert di akhir | O(n) | O(1)* | O(1)** |
| Insert di tengah | O(n) | O(n) | O(n) |
| Delete di awal | O(1) | O(1) | O(n) |
| Delete di akhir | O(n) | O(1)* | O(1) |
| Delete di tengah | O(n) | O(n) | O(n) |
| Akses (Get) | O(n) | O(n) | O(1) |
| Search | O(n) | O(n) | O(n) |
*Dengan tail pointer **Amortized
| Situasi | Rekomendasi |
|---|---|
| Sering insert/delete di awal | Single Linked List |
| Sering insert/delete di kedua ujung | Double Linked List |
| Butuh traversal dua arah | Double Linked List |
| Butuh akses random yang cepat | Array |
| Ukuran data tidak diketahui | Linked List |
| Implementasi Stack | Single Linked List |
| Implementasi Queue | Double Linked List / Circular |
| Implementasi Deque | Double Linked List |
Implementasikan Single Linked List dengan operasi:
- insertAtBeginning
- insertAtEnd
- deleteAtBeginning
- display
Buatlah method getMiddle() yang mengembalikan data node tengah dari linked list. Gunakan teknik two-pointer (slow dan fast pointer).
Buatlah method hasCycle() yang mendeteksi apakah linked list memiliki cycle (node menunjuk ke node sebelumnya). Gunakan Floyd's Cycle Detection Algorithm.
Buatlah method untuk menggabungkan dua sorted linked list menjadi satu sorted linked list.
Implementasikan Stack menggunakan Single Linked List dengan operasi:
- push(data)
- pop()
- peek()
- isEmpty()
Implementasikan Queue menggunakan Double Linked List dengan operasi:
- enqueue(data)
- dequeue()
- front()
- isEmpty()
- Cormen, T. H., et al. (2009). Introduction to Algorithms (3rd ed.). MIT Press.
- Weiss, M. A. (2014). Data Structures and Algorithm Analysis in Java (3rd ed.). Pearson.
- GeeksforGeeks - Linked List Data Structure
- Visualgo - Linked List Visualization








