Pemrograman · Struktur data
Stack dan queue: LIFO vs FIFO dengan contoh Python
Jawaban singkat
Stack adalah kumpulan data di mana item yang terakhir ditambahkan menjadi yang pertama dikeluarkan (LIFO, last in first out), seperti tumpukan piring. Queue adalah kumpulan data di mana item yang pertama ditambahkan menjadi yang pertama dikeluarkan (FIFO, first in first out), seperti antrean di kasir. Keduanya mendukung penambahan dan penghapusan dalam waktu O(1). Di Python, gunakan list sebagai stack dan collections.deque sebagai queue.
Masalah apa yang diselesaikan stack dan queue
Banyak program perlu mengingat item dan memprosesnya nanti dalam urutan tertentu. Stack memberi item terbaru lebih dulu, cocok untuk pekerjaan bersarang: pemanggilan fungsi, riwayat undo, pencocokan tanda kurung, dan depth-first search. Queue memberi item terlama lebih dulu, cocok untuk antrean yang adil: pekerjaan cetak, task scheduler, message queue, dan breadth-first search.
Keduanya adalah abstract data type: didefinisikan oleh operasinya, bukan oleh cara penyimpanannya. Anda bisa membangun salah satunya di atas array atau linked list.
Operasi dan istilahnya
| Operasi | Stack (LIFO) | Queue (FIFO) |
|---|---|---|
| Menambah item | push: taruh di atas | enqueue: tambah di belakang |
| Mengeluarkan item | pop: ambil dari atas | dequeue: ambil dari depan |
| Melihat tanpa mengeluarkan | peek / top | peek / front |
| Tipe di Python | list dengan append dan pop | collections.deque dengan append dan popleft |
| Urutan keluar untuk input 1, 2, 3 | 3, 2, 1 | 1, 2, 3 |
Contoh langkah demi langkah: push dan pop
Masukkan 1, 2, dan 3 ke kedua struktur, lalu keluarkan dua item.
| Langkah | Isi stack (atas di kanan) | Isi queue (depan di kiri) |
|---|---|---|
| tambah 1 | [1] | [1] |
| tambah 2 | [1, 2] | [1, 2] |
| tambah 3 | [1, 2, 3] | [1, 2, 3] |
| keluarkan | mengembalikan 3, sisa [1, 2] | mengembalikan 1, sisa [2, 3] |
| keluarkan | mengembalikan 2, sisa [1] | mengembalikan 2, sisa [3] |
Implementasi di Python
list Python sudah merupakan stack yang baik: append dan pop() bekerja di ujung list dalam waktu O(1) amortized. Untuk queue, jangan pakai list.pop(0), karena ia menggeser semua elemen yang tersisa dan butuh O(n). Gunakan collections.deque, yang O(1) di kedua ujung.
from collections import deque
stack = []
stack.append(1)
stack.append(2)
stack.append(3)
print(stack.pop(), stack[-1]) # 3 2
queue = deque()
queue.append("a")
queue.append("b")
queue.append("c")
print(queue.popleft(), queue[0]) # a b
print(len(stack), len(queue)) # 2 2Jika Anda ingin method bernama dan pesan error yang jelas, bungkus tipe bawaan dalam kelas kecil:
from collections import deque
class Queue:
def __init__(self):
self._items = deque()
def enqueue(self, item):
self._items.append(item)
def dequeue(self):
if not self._items:
raise IndexError("dequeue from empty queue")
return self._items.popleft()
def __len__(self):
return len(self._items)
q = Queue()
q.enqueue("job1")
q.enqueue("job2")
print(q.dequeue(), len(q)) # job1 1Soal stack klasik: tanda kurung seimbang
Untuk memeriksa bahwa setiap tanda kurung ditutup dengan urutan yang benar, push setiap tanda kurung buka. Saat menemukan tanda kurung tutup, elemen teratas stack harus pasangan pembukanya.
def is_balanced(text):
pairs = {")": "(", "]": "[", "}": "{"}
stack = []
for ch in text:
if ch in "([{":
stack.append(ch)
elif ch in pairs:
if not stack or stack.pop() != pairs[ch]:
return False
return not stack
print(is_balanced("f(a[1], {b: 2})")) # True
print(is_balanced("(]")) # False
print(is_balanced("((")) # FalseIde yang sama dipakai untuk mengevaluasi ekspresi dalam notasi Polandia terbalik (reverse Polish notation), mengubah rekursi menjadi loop, dan menjalankan depth-first search: ganti call stack dengan list Anda sendiri.
Soal queue klasik: breadth-first search
Breadth-first search mengunjungi graf level demi level. Queue membuat hal itu terjadi: node yang ditemukan lebih dulu diproses lebih dulu.
from collections import deque
def bfs_order(graph, start):
seen = {start}
queue = deque([start])
order = []
while queue:
node = queue.popleft()
order.append(node)
for nxt in graph[node]:
if nxt not in seen:
seen.add(nxt)
queue.append(nxt)
return order
graph = {"A": ["B", "C"], "B": ["D"], "C": ["D"], "D": []}
print(bfs_order(graph, "A")) # ['A', 'B', 'C', 'D']Kompleksitas waktu dan ruang
| Operasi | Stack (list) | Queue (deque) | Queue (list.pop(0)) |
|---|---|---|---|
| Tambah | O(1) amortized | O(1) | O(1) amortized |
| Hapus | O(1) | O(1) | O(n), elemen bergeser ke kiri |
| Peek | O(1) | O(1) | O(1) |
| Ruang untuk n item | O(n) | O(n) | O(n) |
Amortized berarti append sesekali mengubah ukuran array di baliknya dan butuh O(n), tetapi dirata-ratakan atas banyak operasi, setiap operasi adalah O(1).
Varian dan kesalahan umum
- Deque (double-ended queue): tambah dan hapus di kedua ujung.
collections.dequeadalah salah satunya, dan ia bisa berperan sebagai stack sekaligus queue. - Priority queue: mengeluarkan item terkecil (atau terbesar) lebih dulu, bukan yang terlama. Gunakan
heapq; lihat halaman binary heap. - Circular buffer: queue berukuran tetap yang disimpan dalam array dengan indeks yang berputar.
deque(maxlen=n)membuang item terlama saat penuh. - Queue yang thread-safe:
queue.Queueuntuk thread danasyncio.Queueuntuk coroutine akan menunggu (blocking) sampai ada item. - Queue dari dua stack: push ke in-stack, dan saat out-stack kosong pindahkan semuanya. Setiap item hanya berpindah sekali, jadi operasinya O(1) amortized.
FAQ
Apa perbedaan stack dan queue?
Stack mengeluarkan item yang paling baru ditambahkan lebih dulu (LIFO). Queue mengeluarkan item terlama lebih dulu (FIFO). Keduanya menambah dan menghapus dalam waktu O(1).
Pakai list atau deque untuk queue di Python?
Gunakan collections.deque. Menghapus dari depan list dengan pop(0) itu O(n) karena semua elemen lain bergeser; deque.popleft() adalah O(1).
Di mana stack dipakai pada program nyata?
Call stack yang menyimpan pemanggilan fungsi, riwayat undo dan redo, tombol back di browser, parsing ekspresi, pencocokan tanda kurung, dan depth-first search.
Apa itu stack overflow?
Terjadi saat call stack kehabisan ruang, biasanya karena rekursi yang sangat dalam atau tak terbatas. Di Python muncul sebagai RecursionError ketika batas rekursi terlampaui.
Apakah queue.Queue sama dengan collections.deque?
Tidak. queue.Queue adalah queue yang thread-safe dengan locking serta get dan put yang blocking, untuk mengoper pekerjaan antar thread. collections.deque adalah container serbaguna yang lebih cepat tanpa blocking.