Pohon Biner Lanjut
Mendalami algoritma rekursif tingkat lanjut untuk melakukan pencarian data, deteksi kemiringan pohon, pencarian level, dan penambahan daun.
Navigasi Labirin Bercabang
Pada materi sebelumnya, kita sudah berhasil membangun pohon dan menelusuri isinya. Namun, di dunia nyata, kita sering kali perlu mencari data spesifik atau mengubah struktur pohon, seperti:
- Mengecek keberadaan data tertentu.
- Mencari di tingkat mana sebuah data berada.
- Menambah atau menghapus simpul pada posisi tertentu.
Karena Pohon Biner bercabang, kita tidak bisa mencari data secara lurus. Kita harus "bertanya" ke cabang kiri, dan jika tidak ada, bertanya ke cabang kanan. Proses pencarian ini diselesaikan secara elegan dengan Rekursif.
1. Operasi Searching
Cara mencari nilai X di dalam pohon P mirip dengan seorang manajer yang mencari berkas di kantor:
- Basis: Jika pohon kosong, lapor: "Tidak ketemu" (
return false). - Akar: Jika nilai ada di simpul saat ini, lapor: "Ketemu!" (
return true). - Rekurens: Jika tidak ada, perintahkan cabang kiri untuk mencari. ATAU (
||), jika kiri gagal, perintahkan cabang kanan mencari.
bool SearchTree (Node *P, int x) {
if (IsTreeEmpty(P)) {
return false;
} else {
if (P->info == x) {
return true;
} else {
// Gunakan OR (||). Jika ketemu di kiri, pencarian kanan diabaikan!
return (SearchTree(P->left, x) || SearchTree(P->right, x));
}
}
}
Pencarian Spesifik (SearchDaun)
Jika Anda hanya ingin mencari apakah data ada di posisi Daun (ujung pohon), cukup ubah basisnya. Hentikan pencarian dan cek nilainya saat menemui simpul yang tidak punya anak sama sekali.
2. Deteksi Skewed Tree
Terkadang, pohon biner tumbuh tidak seimbang dan hanya memiliki cabang di satu sisi saja. Kondisi ini disebut Skewed Tree. Jika ini terjadi, performa pencarian akan menurun drastis karena strukturnya menjadi sama seperti Linked List.
Deteksi Condong Kiri
bool IsSkewLeft (Node *P) {
if (IsTreeOneElmt(P)) {
return true;
} else {
if (IsUnerLeft(P)) {
return IsSkewLeft(P->left);
} else {
return false; // Ada cabang kanan? Berarti tidak condong kiri murni!
}
}
}
3. Mencari Level Simpul
Akar selalu berada di Level 1. Anak dari Akar berada di Level 2, dan seterusnya. Untuk mengetahui level dari data X, kita gunakan akumulasi nilai:
int Level (Node *P, int x) {
if (P->info == x) {
return 1; // Basis: Ketemu! Level saya 1 dari titik ini.
} else {
if (SearchTree(P->left, x)) {
return (1 + Level(P->left, x));
} else {
return (1 + Level(P->right, x));
}
}
}
4. Menambah Daun (AddDaun)
Untuk menambah data baru Y sebagai anak dari simpul X, kita harus menelusuri pohon sampai menemukan simpul X yang berstatus sebagai daun.
// Gunakan pointer ganda (Node **P) agar bisa mengubah memori aslinya
void AddDaun (Node **P, int x, int y, bool Kiri) {
if (IsTreeOneElmt(*P) && (*P)->info == x) {
Node *PNew = AlokNode(y);
if (Kiri) (*P)->left = PNew;
else (*P)->right = PNew;
} else {
if (SearchTree((*P)->left, x)) {
AddDaun(&((*P)->left), x, y, Kiri);
} else {
AddDaun(&((*P)->right), x, y, Kiri);
}
}
}
Bahaya Memory Leak saat Menghapus
Saat menghapus simpul menggunakan rekursif (DelDaun), pastikan Anda memutuskan koneksi dari induknya terlebih dahulu SEBELUM memanggil perintah delete. Memori yang terhapus tanpa pemutusan jalur bisa menyebabkan data sampah yang sulit dilacak.