Struktur Data Hirarkis: Heaptree, Binary Tree Traversal
29 Maret 1999
Goal: Heaptree dan kegunaannya dalam heapsort, representasi dinamis dan binary tree traversal
Disclaimer: page ini baru selesai 90% .... jadi jangan buru-buru diprint
Dalam bagian tertentu telah disebutkan bahwa heap adalah bagian dari memori yang terorganisasi untuk dapat melayani alokasi memori secara dinamis. Berikut ini suatu definisi heap (yang lain yang lebih tepatnya disebut heaptree, untuk menyederhanakan kita sekali-sekali menyebutnya dengan kata heap juga) akan dijelaskan.
Suatu Heaptree adalah CBT
dimana harga-harga key pada node-nodenya
sedemikian rupa sehingga haga-harga key
pada node-node childnya tidak ada yang lebih
besar dari parentnya.
Catatan: Tentu saja "lebih besar" bisa
diganti menjadi kebalikannya yaitu "lebih
kecil" jika permasalahannya mendefinisikan
bahwa harga key lebih kecil memiliki prioritas
yang lebih besar. Untuk hal ini maka key dari
root suatu tree/subtree selalu lebih kecil atau
sama dengan key dari node-node di subtree kiri
dan kanannya.
Karena sifatnya itu maka struktur heaptree
bermanfaat untuk mengimplementasikan priority
queue. Sebagai suatu priority queue maka
diperlukan spesifikasi abstraks dari heaptree:
heapify(CBT a)
Key x = remove()
add(Key x)
reheapify()
Kriteria yang penting untuk dipenuhi adalah bahwa
setiap metoda di atas beroperasi pada tree yang
selalu berbentuk CBT karena struktur level lebih
rendahnya tetap merupakan suatu array.
Contoh penggunaan heaptree dalam priority queue di dalam adalah dalam algoritma pengurutan Heapsort. Algoritma pengurutan ini mengurutkan isi suatu array masukan a. Secara konseptual setiap array dapat dipandang sebagai suatu complete binary tree. Dengan metoda heapify maka complete binary tree ini dapat dikonversi menjadi suatu heaptree. Metoda add() tidak diperlukan dalam masalah ini. Setelah dilakukan heapify dan menjadi suatu suatu priority queue maka dengan mengambil data root satu demi satu disertai dengan proses reheapify maka key-key dari data root yang kita ambil secara berturutan itu akan terurut mengecil sampai habis jadi output dituliskan dalam array hasilnya dari kanan ke kiri.
Karena setiap iterasi remove ukuran heaptree berkurang satu dan array hasilny bertambah satu maka untuk optimasi tempat masukan dan keluaran menempati array yang sama dan.operasi remove dimodifikasi sebagai operasi menukarkan isi root dengan elemen terakhir dalam heaptree (setelah penukaran maka elemen terakhir ini bukan lagi menjadi bagian dari heaptree.
Algoritma utamanya:
heapify();
for (i = 0; i < n; i++) {
remove();
reheapify();
}
Algoritma Metoda Heapify()
Ide secara intuitif mungkin adalah melakukan
operasi heapify ini dari root ke arah leaf. Namun
ide ini tidak efisien dalam kenyataannya karena
akan terjadi operasi rutun-naik mirip algoritma
bubble-sort. Ide yang efisien adalah membentuk
heaptree-heaptree mulai dari subtree-subtree yang
paling bawah. Jika subtree-subtree suatu node
sudah membentuk heap maka tree dari node tersebut
mudah dijadikan heaptree dengana mengalirkannya
ke bawah.
Jadi algoritma utamanya beriterasi mulai dari
internal node paling kanan-bawah (atau berindeks
array paling besar) hingga root lalu ke kiri dan
naik ke level di atasnya, dan seterusnya hingga
root (sebagai array [0..N-1] maka iterasi
dilakukan mulai j = N/2, berkurang satu-satu
hingga j = 0.
Algoritma Metoda remove()
Algoritma Metoda reheapify()
heapify()
(karena baik
subtree kiri maupun kanannya merupakan
heap, jadi tidak perlu dilakukan seperti
heapify).Contoh pada pengurutan dalam suatu array
masukkan dengan data 11, 9, 8, 27, 16, 25,
12, 13, 34, 43
. Array ini dapat dipandang
sebagai suatu CBT sbb.
Heapify dilakukan dengan iterasi dari subtree
node ke 4, ke 3, dst. berturut-turut hingga root
menghasilkan operasi-operasi penukaran sbb.
perubahan-perubahan tersebut digambarkan
sebagai berikut.
Semua perubahan di atas terjadi dalam array ybs
hingga diperoleh tree terakhir yang merupakan
heaptree. Dalam iterasi yang melakukan remove()
dan reheapify()
maka akan terjadi:
menjadi | dan data yang telah terurut: 43 |
menjadi | dan data yang telah terurut: 34, 43 |
menjadi | dan data yang telah terurut: 27, 34, 43 |
Node-node saling berhubungan dengan pointer.
Minimal digunakan dua pointer pada setiap node
untuk menunjuk masing-masing ke cabang kiri dan
cabang kanan. Dalam bahasa C misalnya
dideklarasikan dengan: class BinaryTreeNode
{
KeyType Key;
InfoType Info;
BinaryTreeNode Left, Right;
// metoda-metoda
}
Struktur dari binary tree termasuk hubungan-hubungan antara node secara eksplisit direpresentasikan oleh left dan right. Bila diperlukan penelusuran naik (backtrack) maka bisa dilakukan dengan
Alternatif lain, deklarasi ditambah dengan field
ketiga untuk merefer node ayah tsb. namun hal ini
berakibat bertambahnya jumlah tahapan pada
proses-proses penambahan/penghapusan node.
Traversal adalah proses menelusuri satu persatu elemen-elemen data pada struktur. Penelusuran ini tentunya disertai suatu proses tertentu pada node yang didatangi misalnya pencetakan, pencarian, komputasi, atau lain sebagainya. Proses-proses apa pun itu secara umum dapat kita sebut proses mengunjungi.
Cara-cara Penelusuran
penelusuran preorder:
penelusuran postorder:
penelusuran inorder:
Contoh pada binary tree berikut ini dilakukan
traversal:
Perbedaan penelusuran ini dapat dimanfaatkan
untuk konversi infix ke postfix ekspresi
matematis. Contoh: (a+b) * ((d + e - f) / g)
sebagai notasi infix digambarkan dalam
represetnasi tree sbb.
Postorder traversal pada tree akan menghasilkan
ekspresi postfixnya:
Implementasi
Pada repr. Alokasi Dinamis
preOrder() {
visit();
if (left != NULL) left.preOrder();
if (right != NULL) right.preOrder();
}
postOrder() {
if (left != NULL) left.preOrder();
if (right != NULL) right.preOrder();
visit();
}
inOrder() {
if (left != NULL) left.preOrder();
visit();
if (right != NULL) right.preOrder();
}
Dari metoda-metoda penelusuran ini
diperoleh terminologi baru:
Handout berikutnya, atau sebelumnya, atau kembali ke halaman utama