Struktur data dengan JavaScript: Tree
Indonesian (Bahasa Indonesia) translation by Dendi Deden (you can also view the original English article)



Tree adalah salah satu struktur data yang paling umum digunakan dalam pengembangan web. Pernyataan ini berlaku untuk pengguna dan pengembang. Setiap web developer yang telah ditulis HTML dan dimuat ke web browser telah menciptakan sebuah tree, yang disebut sebagai Document Object Model (DOM). Setiap pengguna internet yang memiliki, pada gilirannya, mengkonsumsi informasi di Internet telah menerimanya dalam bentuk tree — DOM.
Sekarang, di sini adalah klimaks: artikel yang Anda baca saat ini dituliskan di peramban sebagai tree! paragprah yang baca direpresentasikan sebagai teks dalam<p>elemen; <p>elemen bersarang di dalam<body>elemen; dan<body>elemen bersarang di dalam<html>elemen.
data Bersarang ini mirip dengan sebuah pohon keluarga. <html>elemen adalah parent,<body>elemen adalah seorang child, dan<p>elemen adalah anak<body>elemen. Jika analogi ini pohon tampaknya berguna bagi Anda, maka Anda akan menemukan kenyamanan dalam mengetahui bahwa analogi lain akan digunakan selama kami pelaksanaan tree.
Dalam artikel ini, kita akan menciptakan sebuah pohon yang menggunakan dua metode yang berbeda dari pohon traversal: Depth-First Search (DFS) dan Breadth-First Search (BFS). (Jika kata traversal asing bagi Anda, mempertimbangkan hal itu berarti mengunjungi setiap node tree.) Kedua jenis traversals menyoroti berbagai cara berinteraksi dengan sebuah pohon. perjalanan kedua, Selain itu, menggabungkan penggunaan struktur data yang kita sudah dibahas dalam seri ini. DFS menggunakan tumpukan dan BFS menggunakan antrian untuk mengunjungi node. Ini keren!
Tree (Depth-First Search dan Breadth-First Search)
Dalam ilmu komputer, tree adalah struktur data yang mensimulasikan hirarkis data dengan node. Setiap node tree memegang sendiri data dan pointer ke node lain.
Terminologi node dan petunjuk mungkin baru bagi beberapa pembaca, jadi mari kita menggambarkan mereka lebih jauh dengan analogi. Mari kita bandingkan tree untuk bagan organisasi. Bagan memiliki posisi tingkat atas (root), seperti CEO. Tepat di bawah posisi ini adalah posisi lain, seperti Wakil Presiden (VP).
Untuk mewakili hubungan ini, kita menggunakan panah yang mengarah dari CEO kepada VP. Posisi, seperti CEO, adalah sebuah node; hubungan yang kita buat dari CEO kepada VP adalah pointer. Untuk membuat hubungan yang lebih dalam bagan organisasi kami, kami hanya mengulangi proses ini-kami memiliki sebuah node yang mengarah ke node lain.
Pada tingkat konseptual, saya berharap bahwa node dan pointer dipahami. Pada tingkat praktis, kita dapat manfaat dari menggunakan sebuah contoh yang lebih teknis. Mari kita mempertimbangkan DOM. DOM memiliki elemen<html>sebagai posisinya top-level (root). Node ini menunjuk kepada<head>elemen dan<body>elemen. Ini proses diulang untuk semua node di DOM.
Salah satu keindahan desain ini adalah kemampuan untuk sarang node: elemen <ul>yang, misalnya, dapat memiliki banyak<li element yang bersarang di dalamnya; Selain itu, setiap<li>elemen dapat memiliki saudara kandung<li>node. Itu aneh, tapi lucu dan benar!
Operasi Tree
Karena setiap tree berisi node, yang dapat constructor yang terpisah dari tree, kami akan menjelaskan operasi konstruktor kedua: Node dan Tree.
Node
-
datamenyimpan nilai. -
parentmenunjuk ke sebuah node parent. -
childrenpoin ke node berikutnya dalam daftar.
Tree
-
_rootpoin untuk root node tree. -
traverseDF(callback)melintasi node pohon dengan DFS. -
traverseBF(callback)melintasi node pohon dengan BFS. -
contains(data, traversal)mencari untuk sebuah node di tree. -
add(data, toData, melintasi)menambahkan sebuah node di tree. -
remove(child, parent)menghapus sebuah node dalam tree.
Implementasi Tree
Sekarang mari kita menulis kode untuk tree!
Properti dari Node
Untuk pelaksanaan, kita pertama akan mendefinisikan fungsi bernama Node dan kemudian constructor yang bernama Tree.
1 |
function Node(data) { |
2 |
this.data = data; |
3 |
this.parent = null; |
4 |
this.children = []; |
5 |
}
|
Setiap contoh node berisi tiga properti: data, parent, dan children. Properti pertama memegang data yang terkait dengan sebuah node. Properti kedua menunjuk satu node. Properti ketiga menunjukkan banyak node children.
Properti Tree
Sekarang, mari kita menentukan konstruktor untuk Tree, yang meliputi konstruktor Node dalam definisi:
1 |
function Tree(data) { |
2 |
var node = new Node(data); |
3 |
this._root = node; |
4 |
}
|
Tree berisi dua baris kode. Baris pertama menciptakan sebuah instance baru dari Node; baris kedua menetapkan node sebagai root dari tree.
Definisi dari Tree dan Node memerlukan hanya beberapa baris kode. Baris-baris ini, namun, yang cukup untuk membantu kami mensimulasikan hirarkis data. Untuk membuktikan hal ini, mari kita gunakan beberapa contoh data untuk membuat sebuah instance dari Tree (dan, secara tidak langsung, Node).
1 |
var tree = new Tree('CEO'); |
2 |
|
3 |
// {data: 'CEO', parent: null, children: []}
|
4 |
tree._root; |
Berkat adanya parent dan children, kita dapat menambahkan node sebagai children _root dan juga menetapkan _root sebagai parent dari node tersebut. Dengan kata lain, kita dapat mensimulasikan penciptaan hirarkis data.
Metode Tree
Selanjutnya, kita akan menciptakan lima metode berikut:
Tree
traverseDF(callback)traverseBF(callback)contains(data, traversal)add(Child, Parent)remove(node, parent)
Karena setiap metode tree mengharuskan kita untuk melintasi pohon, kami pertama akan menerapkan metode yang menentukan jenis tree traversal. (Melintasi tree adalah cara formal mengatakan mengunjungi setiap node tree.)
1 dari 5: traverseDF(callback)
Metode ini melintasi tree dengan depth-first search
1 |
Tree.prototype.traverseDF = function(callback) { |
2 |
|
3 |
// this is a recurse and immediately-invoking function
|
4 |
(function recurse(currentNode) { |
5 |
// step 2
|
6 |
for (var i = 0, length = currentNode.children.length; i < length; i++) { |
7 |
// step 3
|
8 |
recurse(currentNode.children[i]); |
9 |
}
|
10 |
|
11 |
// step 4
|
12 |
callback(currentNode); |
13 |
|
14 |
// step 1
|
15 |
})(this._root); |
16 |
|
17 |
};
|
traverseDF(callback) memiliki parameter bernama callback. Jika tidak jelas dari nama, callback diduga menjadi fungsi, yang akan dipanggil kemudian di traverseDF(callback).
body traverseDF(callback) termasuk fungsi lain yang bernama recurse. Fungsi ini adalah fungsi rekursif! Dengan kata lain, self-invoking dan self-terminating. Menggunakan langkah-langkah yang disebutkan dalam komentar-komentar dari recurse, saya akan menjelaskan proses umum yang recurse menggunakan untuk melintasi seluruh tree.
Berikut adalah langkah-langkah:
- Segera memanggil
recursedengan root node dari tree sebagai argumen. Saat ini,currentNodepoin ke node saat ini. - Masukkan
forloop dan iterate sekali untuk setiap child daricurrentNode, dimulai dengan child pertama. - Di dalam body
forloop, memanggil recurse dengan child daricurrentNode. Anak yang tepat tergantung pada iterasi saat ini dariforloop. - Ketika
currentNodetidak lagi memiliki children, kita keluarforloop dan invokecallbackkami masukan selama invocationtraverseDF(callback).
Langkah 2 (self-terminating), 3 (self-invoking), dan 4 (callback) ulangi sampai kita melintasi setiap node tree.
Rekursi adalah topik yang sangat sulit untuk mengajar dan memerlukan seluruh artikel untuk menjelaskan secara memadai. Karena penjelasan rekursi tidak fokus dari artikel ini — fokus mengimplementasikan tree-saya akan menyarankan bahwa setiap pembaca yang kurang memahami baik dari rekursi melakukan dua hal berikut.
Pertama, bereksperimen dengan pelaksanaan traverseDF(callback) kami saat ini dan mencoba untuk memahami tingkat cara kerjanya. Kedua, jika Anda ingin saya untuk menulis sebuah artikel tentang rekursi, kemudian silakan permintaan itu dalam komentar-komentar dari artikel ini.
Contoh berikut menunjukkan bagaimana tree yang akan dilalui dengan traverseDF(callback). Untuk melintasi tree, saya akan membuat satu dalam contoh di bawah ini. Pendekatan yang saya akan gunakan saat ini tidak ideal, tetapi bekerja. Pendekatan yang lebih baik akan menggunakan add(value), yang kami akan terapkan pada langkah 4 dari 5.
1 |
var tree = new Tree('one'); |
2 |
|
3 |
tree._root.children.push(new Node('two')); |
4 |
tree._root.children[0].parent = tree; |
5 |
|
6 |
tree._root.children.push(new Node('three')); |
7 |
tree._root.children[1].parent = tree; |
8 |
|
9 |
tree._root.children.push(new Node('four')); |
10 |
tree._root.children[2].parent = tree; |
11 |
|
12 |
tree._root.children[0].children.push(new Node('five')); |
13 |
tree._root.children[0].children[0].parent = tree._root.children[0]; |
14 |
|
15 |
tree._root.children[0].children.push(new Node('six')); |
16 |
tree._root.children[0].children[1].parent = tree._root.children[0]; |
17 |
|
18 |
tree._root.children[2].children.push(new Node('seven')); |
19 |
tree._root.children[2].children[0].parent = tree._root.children[2]; |
20 |
|
21 |
/*
|
22 |
|
23 |
creates this tree
|
24 |
|
25 |
one
|
26 |
├── two
|
27 |
│ ├── five
|
28 |
│ └── six
|
29 |
├── three
|
30 |
└── four
|
31 |
└── seven
|
32 |
|
33 |
*/
|
Sekarang, mari kita memanggil traverseDF(callback).
1 |
tree.traverseDF(function(node) { |
2 |
console.log(node.data) |
3 |
});
|
4 |
|
5 |
/*
|
6 |
|
7 |
logs the following strings to the console
|
8 |
|
9 |
'five'
|
10 |
'six'
|
11 |
'two'
|
12 |
'three'
|
13 |
'seven'
|
14 |
'four'
|
15 |
'one'
|
16 |
|
17 |
*/
|
2 dari 5: traverseBF(callback)
Metode ini menggunakan breadth-first search untuk melintasi tree.
Perbedaan antara depth-first search dan pbreadth-first search melibatkan urutan yang mengunjungi node tree. Untuk mengilustrasikan hal ini, mari kita gunakan tree yang kita diciptakan dari traverseDF(callback).
1 |
/*
|
2 |
|
3 |
tree
|
4 |
|
5 |
one (depth: 0)
|
6 |
├── two (depth: 1)
|
7 |
│ ├── five (depth: 2)
|
8 |
│ └── six (depth: 2)
|
9 |
├── three (depth: 1)
|
10 |
└── four (depth: 1)
|
11 |
└── seven (depth: 2)
|
12 |
|
13 |
*/
|
Sekarang, mari kita masukan traverseBF(callback) callback sama yang kita gunakan untuk traverseDF(callback).
1 |
tree.traverseBF(function(node) { |
2 |
console.log(node.data) |
3 |
});
|
4 |
|
5 |
/*
|
6 |
|
7 |
logs the following strings to the console
|
8 |
|
9 |
'one'
|
10 |
'two'
|
11 |
'three'
|
12 |
'four'
|
13 |
'five'
|
14 |
'six'
|
15 |
'seven'
|
16 |
|
17 |
*/
|
Log dari konsol dan diagram tree kami mengungkapkan pola tentang breadth-first search. Mulai dengan root node; Kemudian perjalanan satu kedalaman dan mengunjungi setiap node dalam bahwa kedalaman dari kiri ke kanan. Ulangi proses ini sampai ada kedalaman tidak lebih untuk melakukan perjalanan.
Karena kita memiliki model konseptual breadth-first search mari kita sekarang menerapkan kode yang akan membuat contoh kita bekerja.
1 |
Tree.prototype.traverseBF = function(callback) { |
2 |
var queue = new Queue(); |
3 |
|
4 |
queue.enqueue(this._root); |
5 |
|
6 |
currentTree = queue.dequeue(); |
7 |
|
8 |
while(currentTree){ |
9 |
for (var i = 0, length = currentTree.children.length; i < length; i++) { |
10 |
queue.enqueue(currentTree.children[i]); |
11 |
}
|
12 |
|
13 |
callback(currentTree); |
14 |
currentTree = queue.dequeue(); |
15 |
}
|
16 |
};
|
Definisi kita tentang traverseBF(callback) berisi banyak logika. Untuk alasan ini, saya akan menjelaskan logika dalam langkah-langkah yang dikelola:
- Membuat sebuah instance dari
Queue. - Menambahkan node yang dipanggil
traverseBF(callback)untuk instanceQueue. - Mendeklarasikan variabel bernama
currentNodedan menginisialisasi kenodekami hanya menambahkan ke queue kami. - Sementara
currentNodepoin untuk sebuah node, mengeksekusi kode dalamwhileloop. - menggunakan
forloop untuk interasi pada children daricurrentNode. - Di dalam body
forloop, menambahkan setiap anak untuk queue. - Ambil
currentNodedan masukan sebagai argumencallback. - Menetapkan kembali
currentNodeke node yang dihapus dari queue. - Sampai
currentNodetidak menunjuk ke sebuah node — setiap node dalam tree telah dikunjungi — ulangi langkah 4-8.
3 dari 5: contains(callback, traversal)
Mari kita mendefinisikan sebuah metode yang akan memungkinkan kita untuk mencari untuk nilai yang tertentu di tree kita. Untuk menggunakan salah satu metode kami dari tree traversal, aku sudah didefinisikan contains(callback, traversal) untuk menerima dua argumen: data pencarian dan jenis traversal.
1 |
Tree.prototype.contains = function(callback, traversal) { |
2 |
traversal.call(this, callback); |
3 |
};
|
Dalam body contains(callback, traversal), kami menggunakan metode bernama call untuk memasukan this dan callback. Berisi argumen pertama mengikat traversal menuju tree yang menanggil contains(callback, traversal); argumen kedua adalah fungsi yang dipanggil pada setiap node dalam tree kami.
Bayangkan bahwa kita ingin login ke konsol setiap node yang berisi data dengan angka ganjil dan melintasi setiap node dalam tree kami dengan BFS. Ini adalah kode yang kita akan tulis:
1 |
// tree is an example of a root node
|
2 |
tree.contains(function(node){ |
3 |
if (node.data === 'two') { |
4 |
console.log(node); |
5 |
}
|
6 |
}, tree.traverseBF); |
4 dari 5: add(data, toData, traversal)
Kami sekarang memiliki sebuah metode untuk mencari sebuah node tertentu di tree kita. Mari kita sekarang mendefinisikan sebuah metode yang akan memungkinkan kita untuk menambahkan sebuah node ke node tertentu.
1 |
Tree.prototype.add = function(data, toData, traversal) { |
2 |
var child = new Node(data), |
3 |
parent = null, |
4 |
callback = function(node) { |
5 |
if (node.data === toData) { |
6 |
parent = node; |
7 |
}
|
8 |
};
|
9 |
|
10 |
this.contains(callback, traversal); |
11 |
|
12 |
if (parent) { |
13 |
parent.children.push(child); |
14 |
child.parent = parent; |
15 |
} else { |
16 |
throw new Error('Cannot add node to a non-existent parent.'); |
17 |
}
|
18 |
};
|
add(data, toData, traversal) mendefinisikan tiga parameter. Parameter pertama, data, digunakan untuk membuat sebuah instance baru dari Node. Parameter kedua, toData, digunakan untuk membandingkan terhadap setiap node dalam sebuah tree. Parameter ketiga, traversal, jenis tree traversal digunakan dalam metode ini.
Dalam body add(data, toData, traversal), kita menyatakan ketiga variabel. Variabel pertama, child, diinisialisasi sebagai sebuah instance baru dari Node. Kedua variabel, parent, diinisialisasi sebagai null; tetapi ia kemudian akan menunjuk ke setiap node di tree yang cocok dengan nilai toData. reassignment dari parent yang terjadi dalam variabel ketiga kami menyatakan, yang adalah callback.
callback adalah fungsi yang membandingkan toData untuk setiap node data properti. Jika if pernyataan mengevaluasi true, maka parent diberikan ke node yang cocok dengan if pernyataan.
Perbandingan aktual setiap node untuk toData terjadi di contains(callback, traversal). Jenis traversal dan callback harus dimasukan sebagai argumen dari contains(callback, traversal).
Akhirnya, jika parent ada di pohon, kami mendorong child ke parent.children; Kami juga menetapkan parent untuk parent dari child. Else, kita melempar error
Mari kita gunakan add(data, toData, traversal) dalam sebuah contoh:
1 |
var tree = new Tree('CEO'); |
2 |
|
3 |
tree.add('VP of Happiness', 'CEO', tree.traverseBF); |
4 |
|
5 |
/*
|
6 |
|
7 |
our tree
|
8 |
|
9 |
'CEO'
|
10 |
└── 'VP of Happiness'
|
11 |
|
12 |
*/
|
Berikut adalah contoh yang lebih kompleks add(addData, toData, traversal):
1 |
var tree = new Tree('CEO'); |
2 |
|
3 |
tree.add('VP of Happiness', 'CEO', tree.traverseBF); |
4 |
tree.add('VP of Finance', 'CEO', tree.traverseBF); |
5 |
tree.add('VP of Sadness', 'CEO', tree.traverseBF); |
6 |
|
7 |
tree.add('Director of Puppies', 'VP of Finance', tree.traverseBF); |
8 |
tree.add('Manager of Puppies', 'Director of Puppies', tree.traverseBF); |
9 |
|
10 |
/*
|
11 |
|
12 |
tree
|
13 |
|
14 |
'CEO'
|
15 |
├── 'VP of Happiness'
|
16 |
├── 'VP of Finance'
|
17 |
│ ├── 'Director of Puppies'
|
18 |
│ └── 'Manager of Puppies'
|
19 |
└── 'VP of Sadness'
|
20 |
|
21 |
*/
|
5 dari 5: remove(data, fromData, traversal)
Untuk menyelesaikan implementasi Tree, kita akan menambahkan sebuah metode bernama remove(data, fromData, traversal). Mirip dengan menghapus sebuah node dari DOM, metode ini akan menghapus sebuah node dan semua children.
1 |
Tree.prototype.remove = function(data, fromData, traversal) { |
2 |
var tree = this, |
3 |
parent = null, |
4 |
childToRemove = null, |
5 |
index; |
6 |
|
7 |
var callback = function(node) { |
8 |
if (node.data === fromData) { |
9 |
parent = node; |
10 |
}
|
11 |
};
|
12 |
|
13 |
this.contains(callback, traversal); |
14 |
|
15 |
if (parent) { |
16 |
index = findIndex(parent.children, data); |
17 |
|
18 |
if (index === undefined) { |
19 |
throw new Error('Node to remove does not exist.'); |
20 |
} else { |
21 |
childToRemove = parent.children.splice(index, 1); |
22 |
}
|
23 |
} else { |
24 |
throw new Error('Parent does not exist.'); |
25 |
}
|
26 |
|
27 |
return childToRemove; |
28 |
};
|
Serupa dengan add(data, toData, traversal), Hapus melintasi tree untuk menemukan sebuah node yang berisi argumen kedua, yang sekarang fromData. Jika node ini ditemukan, maka parent poin ke itu.
Saat ini, kita mencapai if pernyataan pertama. Jika parent tidak ada, kita melempar error. Jika parent ada, kita memanggil findIndex() dengan parent.children dan data yang ingin kita Hapus dari node child dari orangtua. (findIndex() adalah metode helper yang aku didefinisikan di bawah ini.)
1 |
function findIndex(arr, data) { |
2 |
var index; |
3 |
|
4 |
for (var i = 0; i < arr.length; i++) { |
5 |
if (arr[i].data === data) { |
6 |
index = i; |
7 |
}
|
8 |
}
|
9 |
|
10 |
return index; |
11 |
}
|
Di dalam findIndex(), logika berikut terjadi. Jika salah satu node dalam parent.children berisi data yang sesuai data, index variabel ditetapkan sebagai integer. Jika tak satu pun dari children data properti sesuai data, kemudian index mempertahankan nilai default dari undefined. Pada baris terakhir dari findIndex(), kita mengembalikan index.
Sekarang kita kembali ke remove(data, fromData, traversal). Jika index adalah undefined, error dilemparkan. Jika index didefinisikan, kita menggunakannya untuk menyambung node yang ingin kita Hapus dari children dari parent; Kami juga menetapkan child dihapus untuk childToRemove.
Akhirnya, kita kembalikan childToRemove.
Implementasi lengkap Tree
Implementasi lengkap Tree. Lihat — kami telah mencapai banyak:
1 |
function Node(data) { |
2 |
this.data = data; |
3 |
this.parent = null; |
4 |
this.children = []; |
5 |
}
|
6 |
|
7 |
function Tree(data) { |
8 |
var node = new Node(data); |
9 |
this._root = node; |
10 |
}
|
11 |
|
12 |
Tree.prototype.traverseDF = function(callback) { |
13 |
|
14 |
// this is a recurse and immediately-invoking function
|
15 |
(function recurse(currentNode) { |
16 |
// step 2
|
17 |
for (var i = 0, length = currentNode.children.length; i < length; i++) { |
18 |
// step 3
|
19 |
recurse(currentNode.children[i]); |
20 |
}
|
21 |
|
22 |
// step 4
|
23 |
callback(currentNode); |
24 |
|
25 |
// step 1
|
26 |
})(this._root); |
27 |
|
28 |
};
|
29 |
|
30 |
Tree.prototype.traverseBF = function(callback) { |
31 |
var queue = new Queue(); |
32 |
|
33 |
queue.enqueue(this._root); |
34 |
|
35 |
currentTree = queue.dequeue(); |
36 |
|
37 |
while(currentTree){ |
38 |
for (var i = 0, length = currentTree.children.length; i < length; i++) { |
39 |
queue.enqueue(currentTree.children[i]); |
40 |
}
|
41 |
|
42 |
callback(currentTree); |
43 |
currentTree = queue.dequeue(); |
44 |
}
|
45 |
};
|
46 |
|
47 |
Tree.prototype.contains = function(callback, traversal) { |
48 |
traversal.call(this, callback); |
49 |
};
|
50 |
|
51 |
Tree.prototype.add = function(data, toData, traversal) { |
52 |
var child = new Node(data), |
53 |
parent = null, |
54 |
callback = function(node) { |
55 |
if (node.data === toData) { |
56 |
parent = node; |
57 |
}
|
58 |
};
|
59 |
|
60 |
this.contains(callback, traversal); |
61 |
|
62 |
if (parent) { |
63 |
parent.children.push(child); |
64 |
child.parent = parent; |
65 |
} else { |
66 |
throw new Error('Cannot add node to a non-existent parent.'); |
67 |
}
|
68 |
};
|
69 |
|
70 |
Tree.prototype.remove = function(data, fromData, traversal) { |
71 |
var tree = this, |
72 |
parent = null, |
73 |
childToRemove = null, |
74 |
index; |
75 |
|
76 |
var callback = function(node) { |
77 |
if (node.data === fromData) { |
78 |
parent = node; |
79 |
}
|
80 |
};
|
81 |
|
82 |
this.contains(callback, traversal); |
83 |
|
84 |
if (parent) { |
85 |
index = findIndex(parent.children, data); |
86 |
|
87 |
if (index === undefined) { |
88 |
throw new Error('Node to remove does not exist.'); |
89 |
} else { |
90 |
childToRemove = parent.children.splice(index, 1); |
91 |
}
|
92 |
} else { |
93 |
throw new Error('Parent does not exist.'); |
94 |
}
|
95 |
|
96 |
return childToRemove; |
97 |
};
|
98 |
|
99 |
function findIndex(arr, data) { |
100 |
var index; |
101 |
|
102 |
for (var i = 0; i < arr.length; i++) { |
103 |
if (arr[i].data === data) { |
104 |
index = i; |
105 |
}
|
106 |
}
|
107 |
|
108 |
return index; |
109 |
}
|
Kesimpulan
Tree mensimulasikan hirarkis data. Sebagian besar dunia di sekitar kita menyerupai jenis hirarki, seperti halaman web dan keluarga kita. Setiap kali Anda menemukan diri Anda membutuhkan struktur data dengan hirarki, pertimbangkan untuk menggunakan sebuah Tree.



