Mata Kuliah: Struktur Data dan Algoritma
Kode: SDA201
SKS: 3 SKS (2 Teori + 1 Praktikum)
Pertemuan: 12
Topik: Binary Search Tree (BST)
Capaian Pembelajaran: Sub-CPMK-5.2 — Mampu mengimplementasikan Binary Search Tree (BST) dan operasi-operasinya
Estimasi Waktu Belajar: 7 jam
Referensi Utama: Cormen Ch.12; Weiss Ch.4.3; Hubbard Ch.11
Setelah menyelesaikan modul ini, mahasiswa diharapkan mampu:
Pada pertemuan sebelumnya (Pertemuan 11), kita telah mempelajari Binary Tree — struktur data hierarkis di mana setiap node memiliki maksimal dua anak (left child dan right child). Binary Tree biasa tidak memiliki aturan khusus tentang bagaimana data disusun, sehingga operasi pencarian memerlukan traversal ke seluruh node dengan kompleksitas O(n).
Binary Search Tree (BST) adalah pengembangan dari Binary Tree dengan menambahkan properti pengurutan yang membuat operasi pencarian menjadi jauh lebih efisien.
Binary Search Tree (BST) adalah Binary Tree yang memenuhi properti berikut: untuk setiap node X, semua nilai di subtree kiri X lebih kecil dari nilai X, dan semua nilai di subtree kanan X lebih besar dari nilai X.
Secara formal, untuk setiap node dengan nilai key:
keykey
Gambar 12.1: Ilustrasi properti Binary Search Tree
struct BSTNode {
int data;
BSTNode* left;
BSTNode* right;
// Constructor
BSTNode(int value) : data(value), left(nullptr), right(nullptr) {}
};
Atau menggunakan template untuk tipe data generik:
template <typename T>
struct BSTNode {
T data;
BSTNode<T>* left;
BSTNode<T>* right;
BSTNode(T value) : data(value), left(nullptr), right(nullptr) {}
};
| Aspek | Binary Tree Biasa | Binary Search Tree |
|---|---|---|
| Pengurutan data | Tidak ada aturan | Terurut (left < parent < right) |
| Kompleksitas search | O(n) | O(log n) rata-rata |
| Kompleksitas insert | O(n) untuk cari posisi | O(log n) rata-rata |
| Kompleksitas delete | O(n) untuk cari posisi | O(log n) rata-rata |
| Inorder traversal | Urutan tidak teratur | Menghasilkan data terurut ascending |
Soal: Diberikan Binary Tree berikut. Tentukan apakah tree tersebut merupakan BST yang valid!
15
/ \
10 20
/ \ / \
5 12 17 25
Penyelesaian:
Untuk memverifikasi BST, periksa setiap node apakah memenuhi properti BST:
Node 15 (root):
Node 10:
Node 20:
Kesimpulan: Ya, tree tersebut adalah BST yang valid.
Soal: Diberikan Binary Tree berikut. Tentukan apakah tree tersebut merupakan BST yang valid!
10
/ \
5 15
/ \
3 12
Penyelesaian:
Periksa setiap node:
Node 10 (root):
Meskipun 12 adalah child kanan dari 5, ia berada di left subtree dari root 10, sehingga harus bernilai < 10.
Kesimpulan: Bukan BST yang valid karena node 12 melanggar properti BST.
Operasi search pada BST memanfaatkan properti pengurutan untuk mengeliminasi setengah tree pada setiap langkah — mirip dengan binary search pada array.
Algoritma:
BSTNode* search(BSTNode* root, int key) {
// Base case: root null atau ditemukan
if (root == nullptr || root->data == key) {
return root;
}
// Key lebih kecil, cari di left subtree
if (key < root->data) {
return search(root->left, key);
}
// Key lebih besar, cari di right subtree
return search(root->right, key);
}
BSTNode* searchIterative(BSTNode* root, int key) {
BSTNode* current = root;
while (current != nullptr) {
if (key == current->data) {
return current; // Ditemukan
} else if (key < current->data) {
current = current->left; // Ke kiri
} else {
current = current->right; // Ke kanan
}
}
return nullptr; // Tidak ditemukan
}

Gambar 12.2: Proses pencarian nilai 17 pada BST
Soal: Diberikan BST dengan struktur berikut. Tuliskan urutan node yang dikunjungi saat mencari nilai 35!
50
/ \
30 70
/ \ / \
20 40 60 80
/
35
Penyelesaian:
Langkah pencarian:
Urutan node yang dikunjungi: 50 → 30 → 40 → 35
Jumlah perbandingan: 4
Soal: Apa yang terjadi jika kita mencari nilai 45 pada BST di Solved Problem 3?
Penyelesaian:
Langkah pencarian:
Hasil: Nilai 45 tidak ditemukan (return nullptr).
Soal: Analisis kompleksitas waktu operasi search pada BST! Jelaskan best case, average case, dan worst case!
Penyelesaian:
Best Case: O(1)
Average Case: O(log n)
Worst Case: O(n)

Gambar 12.3: Perbandingan BST seimbang dan tidak seimbang
Operasi insert pada BST harus memastikan properti BST tetap terjaga setelah penyisipan.
Algoritma:
Catatan: Pada implementasi BST standar, nilai duplikat biasanya tidak diizinkan. Jika ditemukan nilai sama, bisa diabaikan atau menimbulkan error.
BSTNode* insert(BSTNode* root, int value) {
// Base case: posisi kosong ditemukan
if (root == nullptr) {
return new BSTNode(value);
}
// Rekursi ke subtree yang sesuai
if (value < root->data) {
root->left = insert(root->left, value);
} else if (value > root->data) {
root->right = insert(root->right, value);
}
// Jika value == root->data, diabaikan (no duplicates)
return root;
}
BSTNode* insertIterative(BSTNode* root, int value) {
BSTNode* newNode = new BSTNode(value);
// Tree kosong
if (root == nullptr) {
return newNode;
}
BSTNode* current = root;
BSTNode* parent = nullptr;
// Cari posisi yang tepat
while (current != nullptr) {
parent = current;
if (value < current->data) {
current = current->left;
} else if (value > current->data) {
current = current->right;
} else {
// Nilai duplikat, tidak diinsert
delete newNode;
return root;
}
}
// Sisipkan node baru
if (value < parent->data) {
parent->left = newNode;
} else {
parent->right = newNode;
}
return root;
}

Gambar 12.4: Proses penyisipan nilai 25 pada BST
Soal: Gambarkan BST yang dihasilkan dari menyisipkan nilai-nilai berikut secara berurutan: 50, 30, 70, 20, 40, 60, 80
Penyelesaian:
Langkah penyisipan:
BST yang dihasilkan:
50
/ \
30 70
/ \ / \
20 40 60 80
Soal: Gambarkan BST yang dihasilkan dari menyisipkan nilai-nilai berikut secara berurutan: 10, 20, 30, 40, 50
Penyelesaian:
Langkah penyisipan:
BST yang dihasilkan (Degenerate Tree):
10
\
20
\
30
\
40
\
50
Catatan: Jika data diinsert dalam urutan terurut (ascending atau descending), BST akan menjadi degenerate tree dengan tinggi O(n).
Soal: Tuliskan urutan penyisipan yang berbeda untuk nilai {10, 20, 30, 40, 50, 60, 70} agar menghasilkan BST yang seimbang!
Penyelesaian:
Untuk mendapatkan BST seimbang, sisipkan nilai median terlebih dahulu, kemudian median dari subarray.
Strategi:
Urutan penyisipan: 40, 20, 60, 10, 30, 50, 70
BST yang dihasilkan:
40
/ \
20 60
/ \ / \
10 30 50 70
Tinggi tree = 3 (optimal untuk 7 node, karena log₂(7) ≈ 2.8)
Berdasarkan properti BST:
BSTNode* findMin(BSTNode* root) {
if (root == nullptr) {
return nullptr;
}
// Terus ke kiri sampai tidak bisa lagi
while (root->left != nullptr) {
root = root->left;
}
return root;
}
// Versi rekursif
BSTNode* findMinRecursive(BSTNode* root) {
if (root == nullptr || root->left == nullptr) {
return root;
}
return findMinRecursive(root->left);
}
BSTNode* findMax(BSTNode* root) {
if (root == nullptr) {
return nullptr;
}
// Terus ke kanan sampai tidak bisa lagi
while (root->right != nullptr) {
root = root->right;
}
return root;
}
// Versi rekursif
BSTNode* findMaxRecursive(BSTNode* root) {
if (root == nullptr || root->right == nullptr) {
return root;
}
return findMaxRecursive(root->right);
}
| Operasi | Best Case | Average Case | Worst Case |
|---|---|---|---|
| findMin | O(1)* | O(log n) | O(n) |
| findMax | O(1)* | O(log n) | O(n) |
*Best case O(1) terjadi jika min/max adalah root (untuk tree dengan satu node atau skewed tree).
Soal: Pada BST berikut, tentukan nilai minimum dan maksimum!
50
/ \
30 70
/ \ / \
20 40 60 80
/
15
Penyelesaian:
Mencari minimum:
Mencari maksimum:
Soal: Implementasikan fungsi int findKthSmallest(BSTNode* root, int k) yang mencari elemen terkecil ke-k dalam BST!
Penyelesaian:
Elemen ke-k terkecil dapat ditemukan menggunakan inorder traversal karena inorder traversal pada BST menghasilkan elemen terurut ascending.
class Solution {
private:
int count = 0;
int result = -1;
void inorderKth(BSTNode* root, int k) {
if (root == nullptr || count >= k) {
return;
}
// Kunjungi left subtree
inorderKth(root->left, k);
// Process current node
count++;
if (count == k) {
result = root->data;
return;
}
// Kunjungi right subtree
inorderKth(root->right, k);
}
public:
int findKthSmallest(BSTNode* root, int k) {
count = 0;
result = -1;
inorderKth(root, k);
return result;
}
};
Contoh: Untuk BST {15, 20, 30, 40, 50, 60, 70, 80}, k=3 menghasilkan 30.
Operasi delete pada BST adalah operasi paling kompleks karena harus mempertahankan properti BST. Ada tiga kasus yang perlu ditangani:
| Kasus | Kondisi | Solusi |
|---|---|---|
| Kasus 1 | Node adalah leaf (tidak punya anak) | Hapus langsung |
| Kasus 2 | Node punya satu anak | Ganti node dengan anaknya |
| Kasus 3 | Node punya dua anak | Ganti dengan inorder successor atau predecessor |

Gambar 12.5: Penghapusan leaf node pada BST
Implementasi:
// Jika node adalah leaf, parent->left atau parent->right = nullptr

Gambar 12.6: Penghapusan node dengan satu anak pada BST
Implementasi:
// Jika node punya satu anak, ganti node dengan anaknya
// parent->left/right = node->left atau node->right (yang tidak null)
Ini adalah kasus paling kompleks. Ada dua pendekatan:
Inorder Successor adalah node dengan nilai terkecil yang lebih besar dari node yang dihapus.

Gambar 12.7: Penghapusan node dengan dua anak menggunakan inorder successor
BSTNode* deleteNode(BSTNode* root, int key) {
// Base case: tree kosong
if (root == nullptr) {
return nullptr;
}
// Cari node yang akan dihapus
if (key < root->data) {
root->left = deleteNode(root->left, key);
} else if (key > root->data) {
root->right = deleteNode(root->right, key);
} else {
// Node ditemukan - ini yang akan dihapus
// Kasus 1 & 2: Node leaf atau punya satu anak
if (root->left == nullptr) {
BSTNode* temp = root->right;
delete root;
return temp;
} else if (root->right == nullptr) {
BSTNode* temp = root->left;
delete root;
return temp;
}
// Kasus 3: Node punya dua anak
// Cari inorder successor (nilai terkecil di right subtree)
BSTNode* successor = findMin(root->right);
// Copy nilai successor ke node ini
root->data = successor->data;
// Hapus inorder successor
root->right = deleteNode(root->right, successor->data);
}
return root;
}
Soal: Pada BST berikut, tunjukkan hasil penghapusan node 20 (leaf node)!
50
/ \
30 70
/ \
20 40
Penyelesaian:
Kasus: Node 20 adalah leaf (tidak punya anak).
Proses:
Hasil:
50
/ \
30 70
\
40
Soal: Pada BST berikut, tunjukkan hasil penghapusan node 70 (node dengan satu anak)!
50
/ \
30 70
/ \ \
20 40 80
Penyelesaian:
Kasus: Node 70 punya satu anak (80).
Proses:
Hasil:
50
/ \
30 80
/ \
20 40
Soal: Pada BST berikut, tunjukkan hasil penghapusan node 30 (node dengan dua anak)!
50
/ \
30 70
/ \ / \
20 40 60 80
Penyelesaian:
Kasus: Node 30 punya dua anak (20 dan 40).
Proses dengan Inorder Successor:
Hasil:
50
/ \
40 70
/ / \
20 60 80
Alternatif dengan Inorder Predecessor:
Soal: Pada BST berikut, tunjukkan hasil penghapusan node 50 (root dengan dua anak)!
50
/ \
30 70
/ \ / \
20 40 60 80
\
65
Penyelesaian:
Kasus: Node 50 (root) punya dua anak.
Proses dengan Inorder Successor:
Hasil:
60
/ \
30 70
/ \ / \
20 40 65 80
Soal: Tuliskan fungsi bool isBST(BSTNode* root) yang memverifikasi apakah sebuah binary tree adalah BST yang valid!
Penyelesaian:
Pendekatan yang salah adalah hanya memeriksa apakah left < parent < right untuk setiap node. Kita harus memastikan semua node di left subtree lebih kecil dan semua node di right subtree lebih besar.
Pendekatan yang benar: gunakan range checking.
bool isBSTUtil(BSTNode* root, int minVal, int maxVal) {
// Base case: tree kosong adalah BST
if (root == nullptr) {
return true;
}
// Cek apakah nilai node dalam range yang valid
if (root->data <= minVal || root->data >= maxVal) {
return false;
}
// Rekursif: cek left subtree (semua harus < root->data)
// cek right subtree (semua harus > root->data)
return isBSTUtil(root->left, minVal, root->data) &&
isBSTUtil(root->right, root->data, maxVal);
}
bool isBST(BSTNode* root) {
return isBSTUtil(root, INT_MIN, INT_MAX);
}
Alternatif menggunakan inorder traversal:
bool isBSTInorder(BSTNode* root, int& prev) {
if (root == nullptr) {
return true;
}
// Cek left subtree
if (!isBSTInorder(root->left, prev)) {
return false;
}
// Cek current: harus lebih besar dari previous
if (root->data <= prev) {
return false;
}
prev = root->data;
// Cek right subtree
return isBSTInorder(root->right, prev);
}
bool isBST(BSTNode* root) {
int prev = INT_MIN;
return isBSTInorder(root, prev);
}
| Operasi | Best Case | Average Case | Worst Case |
|---|---|---|---|
| Search | O(1) | O(log n) | O(n) |
| Insert | O(1) | O(log n) | O(n) |
| Delete | O(1) | O(log n) | O(n) |
| findMin | O(1) | O(log n) | O(n) |
| findMax | O(1) | O(log n) | O(n) |
| Traversal | O(n) | O(n) | O(n) |
Kompleksitas BST sangat bergantung pada bentuk tree:
| Bentuk Tree | Tinggi | Kompleksitas Operasi |
|---|---|---|
| Perfectly Balanced | ⌊log₂(n)⌋ | O(log n) |
| Reasonably Balanced | O(log n) | O(log n) |
| Skewed/Degenerate | n - 1 | O(n) |
Soal: Hitung jumlah perbandingan yang diperlukan untuk mencari nilai 75 pada kedua BST berikut:
BST A (Balanced):
50
/ \
25 75
/ \ / \
10 30 60 90
BST B (Skewed):
10
\
25
\
30
\
50
\
60
\
75
Penyelesaian:
BST A (Balanced):
Total perbandingan BST A: 2
BST B (Skewed):
Total perbandingan BST B: 6
Kesimpulan: BST balanced (A) memerlukan 3x lebih sedikit perbandingan dibanding BST skewed (B) untuk n=7 node.
BST menjadi tidak seimbang ketika:
| Aspek | BST Seimbang | BST Tidak Seimbang |
|---|---|---|
| Tinggi | O(log n) | O(n) |
| Search | O(log n) | O(n) |
| Insert | O(log n) | O(n) |
| Delete | O(log n) | O(n) |
| Memory overhead | Sama | Sama |
Dalam konteks sistem pertahanan: Jika sistem tracking menggunakan BST tidak seimbang dengan 1 juta data, pencarian bisa memerlukan hingga 1 juta operasi, dibandingkan hanya ~20 operasi pada BST seimbang (log₂(1.000.000) ≈ 20).
Untuk mengatasi masalah BST tidak seimbang, dikembangkan berbagai jenis Self-Balancing BST:
| Tipe | Mekanisme | Kompleksitas Garanteed |
|---|---|---|
| AVL Tree | Balance factor (-1, 0, +1), rotasi | O(log n) |
| Red-Black Tree | Pewarnaan node + rotasi | O(log n) |
| Splay Tree | Splaying (move to root) | Amortized O(log n) |
| B-Tree | Multi-way tree untuk disk | O(log n) |
Catatan: Detail implementasi AVL Tree dan Red-Black Tree akan dipelajari lebih lanjut di mata kuliah lanjutan atau sebagai materi pengayaan. Untuk mata kuliah ini, cukup memahami konsep mengapa balanced BST diperlukan.
Soal: Jelaskan mengapa menyisipkan data {1, 2, 3, 4, 5, 6, 7} secara berurutan menghasilkan BST dengan performa buruk, dan bagaimana menghindarinya!
Penyelesaian:
Masalah:
Menyisipkan {1, 2, 3, 4, 5, 6, 7} berurutan:
1
\
2
\
3
\
4
\
5
\
6
\
7
Hasilnya adalah right-skewed tree dengan:
Solusi:
Soal: Implementasikan class BST lengkap dengan operasi insert, search, delete, findMin, findMax, dan inorder traversal!
Penyelesaian:
#include <iostream>
#include <queue>
using namespace std;
class BST {
private:
struct Node {
int data;
Node* left;
Node* right;
Node(int value) : data(value), left(nullptr), right(nullptr) {}
};
Node* root;
// Helper functions (private)
Node* insertHelper(Node* node, int value) {
if (node == nullptr) {
return new Node(value);
}
if (value < node->data) {
node->left = insertHelper(node->left, value);
} else if (value > node->data) {
node->right = insertHelper(node->right, value);
}
return node;
}
Node* searchHelper(Node* node, int key) {
if (node == nullptr || node->data == key) {
return node;
}
if (key < node->data) {
return searchHelper(node->left, key);
}
return searchHelper(node->right, key);
}
Node* findMinHelper(Node* node) {
if (node == nullptr) return nullptr;
while (node->left != nullptr) {
node = node->left;
}
return node;
}
Node* findMaxHelper(Node* node) {
if (node == nullptr) return nullptr;
while (node->right != nullptr) {
node = node->right;
}
return node;
}
Node* deleteHelper(Node* node, int key) {
if (node == nullptr) return nullptr;
if (key < node->data) {
node->left = deleteHelper(node->left, key);
} else if (key > node->data) {
node->right = deleteHelper(node->right, key);
} else {
// Node ditemukan
if (node->left == nullptr) {
Node* temp = node->right;
delete node;
return temp;
} else if (node->right == nullptr) {
Node* temp = node->left;
delete node;
return temp;
}
// Dua anak: gunakan inorder successor
Node* successor = findMinHelper(node->right);
node->data = successor->data;
node->right = deleteHelper(node->right, successor->data);
}
return node;
}
void inorderHelper(Node* node) {
if (node == nullptr) return;
inorderHelper(node->left);
cout << node->data << " ";
inorderHelper(node->right);
}
void destroyTree(Node* node) {
if (node == nullptr) return;
destroyTree(node->left);
destroyTree(node->right);
delete node;
}
public:
BST() : root(nullptr) {}
~BST() {
destroyTree(root);
}
void insert(int value) {
root = insertHelper(root, value);
}
bool search(int key) {
return searchHelper(root, key) != nullptr;
}
int findMin() {
Node* minNode = findMinHelper(root);
if (minNode == nullptr) {
throw runtime_error("Tree is empty");
}
return minNode->data;
}
int findMax() {
Node* maxNode = findMaxHelper(root);
if (maxNode == nullptr) {
throw runtime_error("Tree is empty");
}
return maxNode->data;
}
void remove(int key) {
root = deleteHelper(root, key);
}
void inorderTraversal() {
inorderHelper(root);
cout << endl;
}
bool isEmpty() {
return root == nullptr;
}
};
// Demo penggunaan
int main() {
BST tree;
// Insert
cout << "Inserting: 50, 30, 70, 20, 40, 60, 80" << endl;
tree.insert(50);
tree.insert(30);
tree.insert(70);
tree.insert(20);
tree.insert(40);
tree.insert(60);
tree.insert(80);
// Inorder traversal
cout << "Inorder traversal: ";
tree.inorderTraversal();
// Search
cout << "Search 40: " << (tree.search(40) ? "Found" : "Not found") << endl;
cout << "Search 45: " << (tree.search(45) ? "Found" : "Not found") << endl;
// Min dan Max
cout << "Minimum: " << tree.findMin() << endl;
cout << "Maximum: " << tree.findMax() << endl;
// Delete
cout << "\nDeleting 20 (leaf)..." << endl;
tree.remove(20);
cout << "Inorder: ";
tree.inorderTraversal();
cout << "Deleting 30 (one child)..." << endl;
tree.remove(30);
cout << "Inorder: ";
tree.inorderTraversal();
cout << "Deleting 50 (two children, root)..." << endl;
tree.remove(50);
cout << "Inorder: ";
tree.inorderTraversal();
return 0;
}
Output:
Inserting: 50, 30, 70, 20, 40, 60, 80
Inorder traversal: 20 30 40 50 60 70 80
Search 40: Found
Search 45: Not found
Minimum: 20
Maximum: 80
Deleting 20 (leaf)...
Inorder: 30 40 50 60 70 80
Deleting 30 (one child)...
Inorder: 40 50 60 70 80
Deleting 50 (two children, root)...
Inorder: 40 60 70 80
BST dapat digunakan untuk menyimpan dan mencari data personel berdasarkan NIP (Nomor Induk Pegawai) dengan efisien.
struct Personel {
string nip; // Key untuk BST
string nama;
string pangkat;
string satuan;
// Operator perbandingan berdasarkan NIP
bool operator<(const Personel& other) const {
return nip < other.nip;
}
};
BST mendukung range query dengan efisien — mencari semua nilai dalam rentang tertentu.
void rangeSearch(BSTNode* root, int low, int high, vector<int>& result) {
if (root == nullptr) return;
// Jika root->data > low, mungkin ada nilai di left subtree
if (root->data > low) {
rangeSearch(root->left, low, high, result);
}
// Jika root->data dalam range, masukkan ke result
if (root->data >= low && root->data <= high) {
result.push_back(root->data);
}
// Jika root->data < high, mungkin ada nilai di right subtree
if (root->data < high) {
rangeSearch(root->right, low, high, result);
}
}
Soal: Sistem radar mendeteksi objek pada jarak tertentu (dalam km). Implementasikan fungsi untuk mencari semua objek dalam jarak 100-200 km menggunakan BST!
Penyelesaian:
#include <iostream>
#include <vector>
using namespace std;
struct RadarContact {
int id;
int distance; // dalam km
string type;
RadarContact(int i, int d, string t) : id(i), distance(d), type(t) {}
};
struct RadarNode {
RadarContact* contact;
RadarNode* left;
RadarNode* right;
RadarNode(RadarContact* c) : contact(c), left(nullptr), right(nullptr) {}
};
class RadarBST {
private:
RadarNode* root;
RadarNode* insert(RadarNode* node, RadarContact* contact) {
if (node == nullptr) {
return new RadarNode(contact);
}
if (contact->distance < node->contact->distance) {
node->left = insert(node->left, contact);
} else {
node->right = insert(node->right, contact);
}
return node;
}
void rangeSearch(RadarNode* node, int minDist, int maxDist,
vector<RadarContact*>& result) {
if (node == nullptr) return;
if (node->contact->distance > minDist) {
rangeSearch(node->left, minDist, maxDist, result);
}
if (node->contact->distance >= minDist &&
node->contact->distance <= maxDist) {
result.push_back(node->contact);
}
if (node->contact->distance < maxDist) {
rangeSearch(node->right, minDist, maxDist, result);
}
}
public:
RadarBST() : root(nullptr) {}
void addContact(RadarContact* contact) {
root = insert(root, contact);
}
vector<RadarContact*> findInRange(int minDist, int maxDist) {
vector<RadarContact*> result;
rangeSearch(root, minDist, maxDist, result);
return result;
}
};
int main() {
RadarBST radar;
// Menambahkan kontak radar
radar.addContact(new RadarContact(1, 50, "Aircraft"));
radar.addContact(new RadarContact(2, 150, "Ship"));
radar.addContact(new RadarContact(3, 75, "Aircraft"));
radar.addContact(new RadarContact(4, 200, "Unknown"));
radar.addContact(new RadarContact(5, 120, "Ship"));
radar.addContact(new RadarContact(6, 180, "Aircraft"));
radar.addContact(new RadarContact(7, 250, "Ship"));
// Mencari objek dalam jarak 100-200 km
cout << "Objek dalam jarak 100-200 km:" << endl;
vector<RadarContact*> targets = radar.findInRange(100, 200);
for (RadarContact* c : targets) {
cout << "ID: " << c->id << ", Distance: " << c->distance
<< " km, Type: " << c->type << endl;
}
return 0;
}
Output:
Objek dalam jarak 100-200 km:
ID: 5, Distance: 120 km, Type: Ship
ID: 2, Distance: 150 km, Type: Ship
ID: 6, Distance: 180 km, Type: Aircraft
ID: 4, Distance: 200 km, Type: Unknown
Soal: Implementasikan fungsi int countNodesInRange(BSTNode* root, int low, int high) yang menghitung jumlah node dengan nilai dalam range [low, high]!
Penyelesaian:
int countNodesInRange(BSTNode* root, int low, int high) {
// Base case
if (root == nullptr) {
return 0;
}
// Jika nilai di luar range kiri, tidak perlu cek left subtree
if (root->data < low) {
return countNodesInRange(root->right, low, high);
}
// Jika nilai di luar range kanan, tidak perlu cek right subtree
if (root->data > high) {
return countNodesInRange(root->left, low, high);
}
// Nilai dalam range: hitung 1 + rekursi ke kedua subtree
return 1 + countNodesInRange(root->left, low, high) +
countNodesInRange(root->right, low, high);
}
Contoh penggunaan:
// BST: 20, 30, 40, 50, 60, 70, 80
// countNodesInRange(root, 30, 60) = 4 (yaitu: 30, 40, 50, 60)
Kompleksitas: O(h + k) dimana h = tinggi tree dan k = jumlah node dalam range.
Soal: Implementasikan fungsi BSTNode* lowestCommonAncestor(BSTNode* root, int p, int q) yang mencari Lowest Common Ancestor (LCA) dari dua node dalam BST!
Penyelesaian:
Lowest Common Ancestor (LCA) dari dua node p dan q adalah node terdalam yang memiliki baik p maupun q sebagai descendant.
Memanfaatkan properti BST untuk mencari LCA secara efisien:
BSTNode* lowestCommonAncestor(BSTNode* root, int p, int q) {
if (root == nullptr) {
return nullptr;
}
// Jika kedua nilai lebih kecil dari root, LCA ada di left subtree
if (p < root->data && q < root->data) {
return lowestCommonAncestor(root->left, p, q);
}
// Jika kedua nilai lebih besar dari root, LCA ada di right subtree
if (p > root->data && q > root->data) {
return lowestCommonAncestor(root->right, p, q);
}
// Jika p dan q berada di sisi berbeda (atau salah satu sama dengan root)
// maka root adalah LCA
return root;
}
Contoh:
50
/ \
30 70
/ \ / \
20 40 60 80
LCA(20, 40) = 30 (keduanya di subtree 30)
LCA(20, 60) = 50 (20 di kiri, 60 di kanan dari 50)
LCA(40, 50) = 50 (50 adalah ancestor dari 40)
Soal: Implementasikan fungsi yang mengkonversi BST menjadi Doubly Linked List (DLL) terurut tanpa menggunakan space tambahan (selain pointer)!
Penyelesaian:
Konversi BST ke DLL dilakukan dengan inorder traversal, menghubungkan left sebagai prev dan right sebagai next.
class BSTtoDLL {
private:
BSTNode* head; // Kepala DLL
BSTNode* prev; // Pointer ke node sebelumnya dalam inorder
void convert(BSTNode* root) {
if (root == nullptr) return;
// Rekursi ke left subtree
convert(root->left);
// Process current node
if (prev == nullptr) {
// Node pertama menjadi head
head = root;
} else {
// Hubungkan prev dengan current
prev->right = root;
root->left = prev;
}
prev = root;
// Rekursi ke right subtree
convert(root->right);
}
public:
BSTNode* convertBSTtoDLL(BSTNode* root) {
head = nullptr;
prev = nullptr;
convert(root);
return head;
}
void printDLL(BSTNode* head) {
cout << "DLL (forward): ";
BSTNode* current = head;
BSTNode* last = nullptr;
while (current != nullptr) {
cout << current->data << " ";
last = current;
current = current->right;
}
cout << endl;
cout << "DLL (backward): ";
while (last != nullptr) {
cout << last->data << " ";
last = last->left;
}
cout << endl;
}
};
Ilustrasi:
BST:
4
/ \
2 5
/ \
1 3
Setelah konversi:
DLL: 1 <-> 2 <-> 3 <-> 4 <-> 5
Dimana:
- node->left = prev pointer
- node->right = next pointer
Kerjakan soal-soal berikut untuk latihan tambahan. Jawaban singkat tersedia di bagian akhir.
Gambarkan BST yang dihasilkan dari menyisipkan nilai: 45, 25, 65, 15, 35, 55, 75
Pada BST di S1, tunjukkan langkah-langkah menghapus node 45 (root)!
Tuliskan fungsi int height(BSTNode* root) yang menghitung tinggi BST!
Implementasikan fungsi BSTNode* buildBalancedBST(int arr[], int start, int end) yang membangun BST seimbang dari array terurut!
Jelaskan bagaimana AVL Tree menjaga keseimbangan dengan menggunakan rotasi!
| Konsep | Deskripsi | Kompleksitas |
|---|---|---|
| BST Property | Left < Parent < Right untuk setiap node | - |
| Search | Memanfaatkan properti untuk eliminasi setengah tree | O(log n) avg, O(n) worst |
| Insert | Cari posisi null yang tepat, sisipkan node baru | O(log n) avg, O(n) worst |
| Delete Leaf | Hapus langsung | O(log n) avg |
| Delete 1 Child | Ganti dengan child | O(log n) avg |
| Delete 2 Children | Ganti dengan inorder successor/predecessor | O(log n) avg |
| findMin | Traverse ke left-most node | O(log n) avg, O(n) worst |
| findMax | Traverse ke right-most node | O(log n) avg, O(n) worst |
| Inorder Traversal | Menghasilkan elemen terurut ascending | O(n) |
| Balanced BST | Self-balancing (AVL, Red-Black) menjamin O(log n) | O(log n) guaranteed |
SP-1:
45
/ \
25 65
/ \ / \
15 35 55 75
SP-2:
SP-3:
int height(BSTNode* root) {
if (root == nullptr) return -1; // atau 0, tergantung definisi
return 1 + max(height(root->left), height(root->right));
}
SP-4:
BSTNode* buildBalancedBST(int arr[], int start, int end) {
if (start > end) return nullptr;
int mid = (start + end) / 2;
BSTNode* root = new BSTNode(arr[mid]);
root->left = buildBalancedBST(arr, start, mid - 1);
root->right = buildBalancedBST(arr, mid + 1, end);
return root;
}
SP-5: AVL Tree menjaga keseimbangan dengan:
This repository is licensed under the Creative Commons Attribution 4.0 International (CC BY 4.0). Commercial use is permitted, provided attribution is given to the author.
© 2026 Anindito