Setelah mempelajari notasi Big-O, Big-Omega, Big-Theta, analisis loop, rekursi, dan amortisasi, kita kini memiliki perangkat lengkap untuk membicarakan kompleksitas algoritma. Chapter ini merangkum kelas kompleksitas yang umum dijumpai di DSA, menyajikan tabel referensi komprehensif kompleksitas algoritma-algoritma klasik, dan menjelaskan metodologi untuk membandingkan dua algoritma secara sistematis. Tabel-tabel di sini akan menjadi rujukan cepat dalam sisa Course ini.

Hierarki Kompleksitas #

Berikut hierarki kelas kompleksitas dari paling cepat ke paling lambat, beserta contoh algoritma untuk masing-masing kelas:

Tabel Pertumbuhan Fungsi #

Tabel berikut menunjukkan nilai numerik untuk berbagai fungsi kompleksitas pada ukuran input berbeda. Gunakan tabel ini untuk memperoleh intuisi tentang skala pertumbuhan.

Fungsi f(n)n=1n=10n=100n=1.000n=10.000n=100.000
1111111
log₂ n03,36,610,013,316,6
√n1,03,210,031,6100,0316,2
n1101001.00010.000100.000
n log₂ n0336649.966132.8771.660.964
n²110010.00010⁶10⁸10¹⁰
n³11.00010⁶10⁹10¹²10¹⁵
2ⁿ21.024≈10³⁰≈10³⁰¹≈10³⁰¹⁰—
n!13,6×10⁶≈9,3×10¹⁵⁷———

Kompleksitas Algoritma Searching #

AlgoritmaBestAverageWorstSpace
Linear searchO(1)O(n)O(n)O(1)
Binary search (iteratif)O(1)O(log n)O(log n)O(1)
Binary search (rekursif)O(1)O(log n)O(log n)O(log n)
Interpolation searchO(log log n)O(log log n)O(n)O(1)
Exponential searchO(1)O(log n)O(log n)O(1)
Ternary searchO(1)O(log₃ n)O(log₃ n)O(1)
Jump searchO(1)O(√n)O(√n)O(1)

Kompleksitas Algoritma Sorting #

AlgoritmaBestAverageWorstSpaceStable
Bubble sortO(n)O(n²)O(n²)O(1)Ya
Selection sortO(n²)O(n²)O(n²)O(1)Tidak
Insertion sortO(n)O(n²)O(n²)O(1)Ya
Shell sortO(n log n)O(n^1.25)O(n²)O(1)Tidak
Merge sortO(n log n)O(n log n)O(n log n)O(n)Ya
Quick sort (random pivot)O(n log n)O(n log n)O(n²)O(log n)Tidak
Heap sortO(n log n)O(n log n)O(n log n)O(1)Tidak
Counting sortO(n + k)O(n + k)O(n + k)O(n + k)Ya
Radix sortO(d·(n + k))O(d·(n + k))O(d·(n + k))O(n + k)Ya
Bucket sortO(n + k)O(n + k)O(n²)O(n + k)Ya

Kompleksitas Struktur Data #

Struktur DataAccessSearchInsertDeleteSpace
Array statisO(1)O(n)O(n)O(n)O(n)
std::vector (dinamis)O(1)O(n)O(1) amortizedO(n)O(n)
Singly linked listO(n)O(n)O(1) (di kepala)O(1) (di kepala)O(n)
Doubly linked listO(n)O(n)O(1) (di ujung)O(1) (di ujung)O(n)
Stack (array)——O(1)O(1)O(n)
Queue (array)——O(1)O(1)O(n)
Hash table ( chaining)—O(1) avg / O(n) worstO(1) avgO(1) avgO(n)
Binary search tree (balanced)O(log n)O(log n)O(log n)O(log n)O(n)
Binary search tree (unbalanced)O(n)O(n)O(n)O(n)O(n)
AVL tree / Red-Black treeO(log n)O(log n)O(log n)O(log n)O(n)
Heap (binary)O(1) (peek)O(n)O(log n)O(log n)O(n)
TrieO(L)O(L)O(L)O(L)O(Σ·L)

Kompleksitas Algoritma Graph #

AlgoritmaTime ComplexitySpace
BFS (adjacency list)O(V + E)O(V)
DFS (adjacency list)O(V + E)O(V)
BFS (adjacency matrix)O(V²)O(V)
DFS (adjacency matrix)O(V²)O(V)
Dijkstra (binary heap)O((V + E) log V)O(V)
Dijkstra (Fibonacci heap)O(E + V log V)O(V)
Bellman-FordO(V · E)O(V)
Floyd-WarshallO(V³)O(V²)
Kruskal (sort + DSU)O(E log E)O(V + E)
Prim (binary heap)O(E log V)O(V)
Topological sort (DFS)O(V + E)O(V)
Tarjan SCCO(V + E)O(V)
Ford-Fulkerson (Edmonds-Karp)O(V · E²)O(V + E)

Kompleksitas Algoritma String #

AlgoritmaTimePreprocessSpace
Naive string matchO(n·m)—O(1)
Rabin-KarpO(n+m) avg / O(n·m) worstO(m)O(1)
KMP (Knuth-Morris-Pratt)O(n + m)O(m)O(m)
Z-algorithmO(n + m)O(n + m)O(n + m)
Aho-CorasickO(n + m + z)O(m · Σ)O(m · Σ)
Suffix array (DC3)O(n)—O(n)
Suffix array (sort-based)O(n log n)—O(n)
Suffix tree (Ukkonen)O(n)—O(n)

Metodologi Membandingkan Dua Algoritma #

Saat dihadapkan pada dua algoritma yang menyelesaikan masalah yang sama, kita perlu metodologi sistematis untuk memilih. Berikut langkah-langkah yang dianjurkan:

1. Bandingkan Asimptotik (Big-Theta) #

Mulai dari kelas asimptotik. Bila A = Θ(n log n) dan B = Θ(n²), maka A menang untuk n besar tanpa syarat. Bila keduanya sama kelasnya, lanjut ke langkah berikutnya.

2. Bandingkan Konstanta (Empiris atau Teoritis) #

Bila kedua algoritma Θ(n log n), konstanta menjadi pembeda. Contoh: merge sort vs heap sort keduanya Θ(n log n), tetapi merge sort biasanya lebih cepat di praktik karena akses memori lebih sekuensial.

3. Pertimbangkan Kasus Spesial #

Beberapa algoritma unggul pada input tertentu: insertion sort cepat pada array hampir terurut (Θ(n)); binary search cepat pada array terurut (Θ(log n)); counting sort cepat bila rentang nilai kecil (Θ(n + k)).

4. Faktor Memori #

Pada perangkat dengan RAM terbatas, algoritma in-place seperti heap sort menjadi pilihan meski sedikit lebih lambat.

5. Benchmark Konkret #

Setelah analisis asimptotik, uji dengan data realistis. Profiling mengungkap efek cache, branch prediction, dan overhead yang tidak terlihat dalam analisis.

Kode: Membandingkan Bubble vs Insertion Sort pada Array Hampir Terurut #

cpp
#include <iostream>
#include <vector>
#include <chrono>

long long cmpBubble = 0, cmpInsert = 0;

void bubbleSort(std::vector<int>& v) {
    cmpBubble = 0;
    int n = static_cast<int>(v.size());
    for (int i = 0; i < n - 1; ++i) {
        bool tukar = false;
        for (int j = 0; j < n - i - 1; ++j) {
            ++cmpBubble;
            if (v[j] > v[j + 1]) {
                std::swap(v[j], v[j + 1]);
                tukar = true;
            }
        }
        if (!tukar) break;
    }
}

void insertionSort(std::vector<int>& v) {
    cmpInsert = 0;
    for (std::size_t i = 1; i < v.size(); ++i) {
        int key = v[i];
        int j = static_cast<int>(i) - 1;
        while (j >= 0) {
            ++cmpInsert;
            if (v[j] > key) { v[j + 1] = v[j]; --j; }
            else break;
        }
        v[j + 1] = key;
    }
}

int main() {
    // Array hampir terurut: 95% terurut, 5% acak
    std::vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 12, 10, 11, 9, 13, 14, 15};
    auto b = a;

    bubbleSort(a);
    insertionSort(b);

    std::cout << "Array 15 elemen, hampir terurut\n";
    std::cout << "Bubble sort    : " << cmpBubble << " pembandingan\n";
    std::cout << "Insertion sort : " << cmpInsert << " pembandingan\n";
    return 0;
}

Output yang Dihasilkan:

text
Array 15 elemen, hampir terurut
Bubble sort    : 50 pembandingan
Insertion sort : 19 pembandingan

Bedah Kode Baris-per-Baris #

  1. Variabel cmpBubble dan cmpInsert: penghitung pembandingan global. Keduanya berkelas asimptotik sama (O(n²) worst), tetapi kita ingin melihat konstanta pada kasus hampir terurut.
  2. Baris bool tukar = false;: optimasi early termination pada bubble sort. Bila satu pass tidak ada pertukaran, array sudah terurut.
  3. Array {1, 2, 3, 4, 5, 6, 7, 8, 12, 10, 11, 9, 13, 14, 15}: array hampir terurut, hanya 3 elemen yang tidak pada posisi tepat.
  4. Output: bubble sort memerlukan 50 pembandingan, insertion sort hanya 19. Selisih besar menunjukkan insertion sort unggul pada input hampir terurut, meskipun keduanya sama-sama Θ(n²) worst case.
  5. Implikasi: meskipun kelas asimptotik sama, konstanta dan adaptasi terhadap input dapat memberi perbedaan dramatis. Inilah mengapa analisis kompleksitas perlu dilengkapi dengan uji empiris.

Aturan Praktis Memilih Algoritma #

SituasiAlgoritma yang Disarankan
n kecil (< 50)Insertion sort, linear search
n sedang (50–10.000), tidak terurutQuick sort, hash table
n besar (> 10.000), perlu stabilMerge sort
n sangat besar, perlu in-placeHeap sort
Rentang nilai kecil (misal 0–255)Counting sort
Data string panjangRadix sort
Data terurut, perlu cariBinary search
Data tidak terurut, perlu cariHash table
Update sering, query max/minHeap
Konektivitas graphUnion-Find
Jarak terpendek, satu sumberDijkstra (non-negatif), Bellman-Ford (umum)
Jarak terpendek, semua pasangFloyd-Warshall (V kecil), Johnson (V besar)

Ringkasan #

  • Hierarki kompleksitas: 1 < log n < √n < n < n log n < n² < n³ < 2ⁿ < n!.
  • Tabel referensi kompleksitas searching, sorting, struktur data, graph, dan string menyediakan rujukan cepat.
  • Saat membandingkan dua algoritma: mulai dari asimptotik, lalu konstanta, lalu kasus spesial, lalu faktor memori, lalu benchmark.
  • Tidak ada algoritma terbaik universal; pemilihan selalu melibatkan trade-off.

Pada Section berikutnya, analisis-dan-pembuktian-algoritma, kita akan beralih dari pertanyaan “seberapa cepat” ke pertanyaan “apakah benar”. Kita akan mempelajari loop invariant, induksi matematis, dan pembuktian kebenaran algoritma secara formal.