Stack dan Queue

Stack adalah struktur data yang mengikuti prinsip Last-In-First-Out atau LIFO, mirip seperti tumpukan piring di mana piring terakhir yang ditaruh adalah yang pertama diambil. Bayangkan Anda memasukkan buku ke dalam kotak vertikal, buku terakhir yang masuk akan berada di atas dan diambil pertama kali.

Queue mengikuti prinsip First-In-First-Out atau FIFO, seperti antrian di kasir supermarket. Orang yang datang pertama akan dilayani pertama. Dalam programming, queue sering digunakan untuk task scheduling, breadth-first search, dan buffering.

Kompleksitas Operasi

Untuk stack, operasi push (menambah elemen) dan pop (mengambil elemen) keduanya memiliki kompleksitas O(1) karena kita selalu beroperasi di ujung yang sama. Peek (melihat elemen teratas tanpa menghapus) juga O(1). Sama halnya dengan queue, enqueue (menambah di belakang) dan dequeue (mengambil dari depan) adalah O(1) jika diimplementasikan dengan benar menggunakan linked list atau circular array.

Contoh Implementasi Stack

package main

import (
    "errors"
    "fmt"
)

// Stack menggunakan slice sebagai underlying storage
type Stack struct {
    items []int
}

// Push menambahkan elemen ke top stack
// Kompleksitas Waktu: O(1) amortized - slice di Go otomatis expand
// Kompleksitas Ruang: O(1) per operasi
func (s *Stack) Push(value int) {
    s.items = append(s.items, value)
}

// Pop menghapus dan mengembalikan elemen dari top
// Kompleksitas Waktu: O(1)
// Kompleksitas Ruang: O(1)
func (s *Stack) Pop() (int, error) {
    if s.IsEmpty() {
        return 0, errors.New("stack is empty")
    }
    
    // Ambil elemen terakhir
    index := len(s.items) - 1
    value := s.items[index]
    
    // Hapus elemen terakhir dengan slicing
    s.items = s.items[:index]
    
    return value, nil
}

// Peek melihat elemen top tanpa menghapus
// Kompleksitas Waktu: O(1)
// Kompleksitas Ruang: O(1)
func (s *Stack) Peek() (int, error) {
    if s.IsEmpty() {
        return 0, errors.New("stack is empty")
    }
    return s.items[len(s.items)-1], nil
}

// IsEmpty mengecek apakah stack kosong
func (s *Stack) IsEmpty() bool {
    return len(s.items) == 0
}

// Size mengembalikan jumlah elemen
func (s *Stack) Size() int {
    return len(s.items)
}

Studi Kasus: Valid Parentheses

Problem ini sangat umum dan mendemonstrasikan penggunaan stack yang sempurna. Bayangkan Anda sedang memeriksa kode programming untuk memastikan setiap kurung buka memiliki pasangan kurung tutup yang sesuai.

Contoh Implementasi Queue

Studi Kasus: Implement Queue using Stacks

Ini adalah problem interview klasik yang menguji pemahaman Anda tentang kedua struktur data. Idenya adalah menggunakan dua stack untuk mensimulasikan behavior queue.

Penjelasan Kompleksitas Queue using Stacks

Meskipun operasi dequeue bisa memerlukan O(n) dalam satu pemanggilan (ketika harus transfer semua elemen), kompleksitas amortized tetap O(1). Ini karena setiap elemen hanya dipindahkan dari stackIn ke stackOut sekali saja. Jika Anda melakukan n operasi enqueue diikuti n operasi dequeue, total work adalah 3n operasi (n push ke stackIn, n transfer ke stackOut, n pop dari stackOut), yang memberikan average O(1) per operasi.

Last updated