tree - sci.feu.ac.thsci.feu.ac.th/faa/dsa/bookpdfs/chap6-binarytree.pdf · o binary search tree 6.1...
TRANSCRIPT
Tree เปนโครงสรางหลกอกชนดหนงทสามารถน ามาใชในการจดการกบขอมลไดอยางมประสทธภาพอกรปแบบหนง การจดเกบดวยการใช tree กคลายกบการจดเกบดวย Linked-List เพยงแตมเงอนไข และวธการในการจดการทตางกน โดยทวไปในระบบปฏบตการ การจดเกบไฟลมกจะใช tree หรอโครงสรางทมรปแบบคลายกบ tree เปนตวจดเกบ ในบทนเราจะมาท าความรจกกบ tree ชนดหนงทมช อเรยกวา Binary Tree หลงจากจบบทเรยนนแลว ผอานจะไดทราบถง o โครงสรางของ Binary tree o การน าขอมลเขาส Binary tree o การเขาหา Binary tree ในรปแบบของ
o Pre-Order Traversal o In-Order Traversal o Post-Order Traversal o Level-Order Traversal
o Binary Search Tree 6.1 ขอมลท วไปของ Tree โครงสรางทมหนาตาคลาย Tree โดยทวไปทเราเหนกนบอย ๆ ในการใชคอมพวเตอรมกจะเปนโครงสรางทแสดงถงไฟลทมอยในแฟมใดแฟมหนง (ถาใช Windows) และมรปรางหนาตา คลาย ๆ กบภาพทเหนน ภาพทางซายเปน Directory tree ทเปนอยจรงใน Windows สวนภาพทางขวามอเปนภาพจ าลองจากภาพทางซายเพอใหเหนถงโครงสรางทมสวนคลายกบ Tree
จากโครงสรางของแฟมทเหน เรามแฟม Phoenix อยดานบนสด ถดมาอกระดบหนงมแฟม 107221 แฟม basic-java, และแฟม bc221Book และภายในแฟม basic-java เรามแฟมอกสองแฟมคอ แฟม Art และแฟม Code ส าหรบแฟม bc221Book เรามสแฟมคอ แฟม PDF Format,
PDF Format
source
basic-java
Phoenix (E:)
107221 bc221Book
Art Code pics Word Format
Sample
oneMore
Binary Tree บทท 6
152
แฟม pics, แฟม source, และแฟม Word Format ในแฟม source เรามแฟม Sample ซงในแฟมนมแฟม oneMore อยอกหนงแฟม สวนแฟม Word Format นนไมมแฟมใดอยภายในเลย ถงแมวาการจดเกบไฟลทเหนจะมหนาตาคลายกบ Tree แตกยงไมใช Tree เสยทเดยว เนองจากวาภายในแฟมของ Windows ทเปน directory นนจะมแฟมอยอกสองแฟมคอ แฟม . และแฟม .. ซงเปนแฟมทอางถงตวเอง และอางถงแฟมทอยถดไปดานบน (parent directory) ซงผอานสามารถดไดจากการใชค าสง dir ใน Command prompt โดยทวไป Tree ประกอบไปดวย node หลาย ๆ ตวทเช อมตอกนดวย edge ดงแสดงใหเหนในภาพท 6.1
ภาพท 6.1 โครงสรางของ Tree โดยทวไป
กอนทเราพดถงโครงสรางหลกทใชในการจดการขอมลของ Tree เราควรทจะรถงนยามตาง ๆ ทใชใน Tree โดยทวไป ดงน Path หมายถง เสนทางจาก node ใด node หนงไปยง node สดทายทอยในเสนทางนน
Edge หมายถงเสนทางเชอมตอระหวาง node สอง node (บางครงเรยกวา link) Root หมายถง node ทอยบนสดใน tree นน ๆ ซงมเพยง node เดยวเทานน และเสนทางจาก node ใด ๆ ทอยใน tree ไปยง root จะมเพยงเสนทางเดยวเทานน Parent หมายถง node ทม node อน ๆ เชอมตอกบตวของมนเอง (ยกเวน root) ซง node ทเชอมตอนจะอยทางดานลางของ node ทเปน parent Child หมายถง node ทเชอมตอกบ node ทอยทางดานบน (node ลก) Leaf หมายถง node ทไมม node อน ๆ เชอมตออยทางดานลาง (no children) Sub-tree หมายถง กลมของ node ทอยใน tree โดยม node ใด node หนงเปน root Visiting หมายถง กระบวนการตาง ๆ ทสามารถกระท าไดใน tree นน ๆ เชน print คาของ node ใด node หนงหรอเปลยนคาของขอมลทเกบอยใน node นน ๆ กได Traversing หมายถงการเขาหา node ทมอยทก node ใน tree นน ๆ Level (หรอ height) หมายถงระดบชนของ tree วามกระดบ เชน ถา root เปนระดบ 0 ลก (children) ของ root กจะอยทระดบ 1 และหลานของ root จะอยทระดบ 2 เปนตน
Node
Edge
บทท 6 Binary Tree
153
Tree มรปรางหนาตาทแตกตางกนออกไป มากมายทงนกข นอยกบการออกแบบ และการก าหนดวา Tree ควรจะมรปรางทเหมาะสมกบการใชงานอยางไร ในบทนเราจะมาท าความรจกกบ Binary Tree ซงเปน Tree แบบหนงทมการน าไปใชในการจดเกบขอมลมากพอสมควร 6.2 Binary Tree
Binary tree เปน tree ท node แตละ node สามารถทจะมลก (children) ไดสงสด 2 node อยทางซายหนง node อยทางขวาหนง node และ node ทอยใน Binary tree ไมจ าเปนทจะตองมลกอยทงสองขางอาจมลกเพยงขางเดยวกได หรอไมจ าเปนตองมลกเลยกได ซงถาไมมลกอยเลยตวมนเองกคอ leaf node นนเอง ในการออกแบบ node ทตองใชส าหรบ Binary tree นนเราสามารถท าไดหลายแบบ ทงนกตองข นอยกบการใชงานของ Binary tree นน ส าหรบ node ทเราออกแบบนจะเปน node ทเกบขอมลตามความตองการของผใช ซงมโครงสรางดงน class BinaryNode<T extends Comparable> {
private T item;
private BinaryNode<T> left, right;
…
…
}
โครงสรางทไดออกแบบไว มสมาชกอยสามตวคอ ขอมลทอยใน node (item) ตวเชอม node ซาย (left) และตวเชอม node ขวา (right) เราไดท าการตดเอา code สวนอน ๆ ออกเพอใหเหนเฉพาะโครงสรางส าคญทงสามตวน (สมาชกอน ๆ ทเหลอเปน method ทท าหนาทตาง ๆ กน) ภาพท 6.2 แสดงถงโครงสรางของ node ทวาน
ภาพท 6.2 โครงสรางของ node ส าหรบใชใน Binary tree (L = left node, R = right node)
ในการน าขอมลเขาส node นนเรากอาจท าไดสองวธคอ 1) ผานทาง constructor และ 2) ผานทาง method ส าหรบการน าเขาทเราไดออกแบบนนเราใชทงสองวธ เพราะท าใหการน าขอมลเขาส node ของเรานนงายขน กอนทเราจะอธบายถงการท างานในสวนตาง ๆ เราไดน าเอา code ทงหมดของ BinaryNode มาใหดกอน
1: /**
2: Simple BinaryNode for Binary tree
3: */
4:
5: class BinaryNode<T extends Comparable> {
6: public T item;
7: public BinaryNode<T> left, right;
8:
9: //for empty node
10: BinaryNode() {
11: item = null;
12: left = right = null;
13: }
14:
15: BinaryNode(T item) {
16: this.item = item;
17: left = right = null;
18: }
19:
20: //assign data to this node and set
null หรอ node อน null หรอ node อน
item
L R
Binary Tree บทท 6
154
21: //left and right node to given nodes, respectively
22: BinaryNode(T item, BinaryNode<T> left, BinaryNode<T> right) {
23: this.item = item;
24: this.left = left;
25: this.right = right;
26: }
27:
28: //calculate number of nodes
29: public int size(BinaryNode<T> t) {
30: if(t == null)
31: return 0;
32: else
33: return size(t.left) + size(t.right) + 1;
34: }
35:
36: //calculate height
37: public int height(BinaryNode<T> t) {
38: if(t == null)
39: return -1;
40: else
41: return Math.max(height(t.left), height(t.right)) + 1;
42: }
43:
44: //print data of node in Pre-order fashion
45: public void preorderPrint() {
46: System.out.print(item + " ");
47: if(left != null) {
48: left.preorderPrint();
49: }
50: if(right != null) {
51: right.preorderPrint();
52: }
53: }
54:
55: //print data of node in In-order fashion
56: public void inorderPrint() {
57: if(left != null) {
58: left.inorderPrint();
59: }
60: System.out.print(item + " ");
61: if(right != null) {
62: right.inorderPrint();
63: }
64: }
65:
66: //print data of node in Post-order fashion
67: public void postorderPrint() {
68: if(left != null) {
69: left.postorderPrint();
70: }
71: if(right != null) {
72: right.postorderPrint();
73: }
74: System.out.print(item + " ");
75: }
76: }
เราม constructor สองตวคอ ตวทไมม parameter และตวทม parameter ซงมทใชตางกน คอ เราจะใช constructor ตวทไมม parameter เปนตวสราง node ทไมมขอมลอยเลย พรอมทงก าหนดให field ทงสอง (left และ right) มคาเปน null คอไมมการเชอมตอกบ node ใด ๆ เลย สวนตวทสอง เราก าหนดคาใหกบ field ทงสามของ node ตามสงทสงเขามาทาง parameter ซงกคอ ตวแรกเปนคาของขอมลทอยใน node สวนอกสองคาเปน node ทตองถกเชอมกบ node น ส าหรบ method ตวทอ น ๆ ทเหลออยนนเราจะไดอธบายในโอกาสตอไป หลงจากทมโครงสรางของ node เรยบรอยแลว เรากตองมาออกแบบโครงสรางของ Binary tree ทเราตองการใชในการจดการกบขอมลของเรา ซงส งส าคญทเราตองท านอกเหนอจากการน าขอมลเขากคอ การเชอม node ตาง ๆ เขาดวยกน เรามาดภาพของ Binary tree ทมการเชอม
node วามหนาตาอยางไร ถาน า node ทเราไดออกแบบมาใช
บทท 6 Binary Tree
155
ภาพท 6.3 โครงสรางของ Binary tree
ในการเขยน code ของ Binary tree ตามทเราไดออกแบบไวนนเรากไมตองท าอะไรมากเพยงแต เรยกใช constructor ของ node เปนตวจดการใหเรา ดงน
1: /**
2: Simple Binary tree
3: */
4:
5: class BinaryTree<T extends Comparable> {
6: private BinaryNode<T> root;
7:
8: //create an empty tree
9: BinaryTree() {
10: root = null;
11: }
12:
13: //tree with one node
14: BinaryTree(T item) {
15: root = new BinaryNode<T>(item, null, null);
16: }
17:
18: //calculate size of tree
19: public int size() {
20: return root.size(root);
21: }
22:
23: //calculate height of tree
24: public int height() {
25: return root.height(root);
26: }
27:
28: //make this tree with given data and
29: //connect its left and right to the given trees
30: public void makeTree(T item, BinaryTree<T> left, BinaryTree<T> right) {
31: root = new BinaryNode<T>(item, left.root, right.root);
32: }
33:
34: //return true if tree is empty
35: private boolean empty() {
36: if(root == null)
37: return true;
38: else
39: return false;
40: }
41:
root
item
L R
item
L R
item
L R
item
L R
null null null
null null
Binary Tree บทท 6
156
42: //print data of each node in tree
43: public void printBinaryTree() {
44: System.out.print("Items in tree: ");
45: if(!empty())
46: root.postorderPrint();
47: else
48: System.err.println("Sorry! Tree is empty.");
49: System.out.println();
50: }
51: }
จากไฟล BinaryTree.java เราจะเหนวาม constructor อยสองตวโดยตวแรกจะเปนตวสราง Binary tree ทม node ทไมมขอมลเพยง node เดยวเทานน (ซงเราเรยกวา root node) สวน constructor ตวทสองเราก าหนดใหเปน constructor ทน าขอมลเขาส node พรอมทงก าหนดให left และ right มคาเปน null ซงเราจะใชเปนตวเชอมกบ node อน ๆ ตอไป สวนการสราง Binary tree นนเราใช makeTree() เปนตวจดการใหเรา ซง makeTree() จะม parameter อยสามตวคอ
1. ขอมลของ node ใหมน (T item) 2. node ทอยทางดานซายของ node น (BinaryTree<T> left) 3. node ทอยทางดานขวาของ node น (BinaryTree<T> right)
และภายใน makeTree() เรากสราง node ขนมาใหมผานทาง constructor ของ BinaryNode ดงน root = new BinaryNode<T>(item, left.root, right.root);
ซงค าสงดงกลาวจะท าการสราง node ใหมทมขอมลเปน item และท าการเชอม left ของ node ใหมเขากบ root ของ node ทเขามา (node ทเขามามชอวา left ดงนนจงตองเรยก left.root) รวมทงเชอม right ของ node ใหมนเขากบ root ของ node ทเขามาดวยเชนกน เพราะฉะนนถาเราลองเรยก makeTree() ดวยขอมลน BinaryTree<Integer> t1 = new BinaryTree<Integer>();
BinaryTree<Integer> t2 = new BinaryTree<Integer>();
BinaryTree<Integer> t3 = new BinaryTree<Integer>(3);
BinaryTree<Integer> t4 = new BinaryTree<Integer>(4);
BinaryTree<Integer> t5 = new BinaryTree<Integer>();
BinaryTree<Integer> t6 = new BinaryTree<Integer>(6);
//connect those trees together
t5.makeTree(5, t6, new BinaryTree<Integer>());
t2.makeTree(2, t4, t5);
t1.makeTree(1, t2, t3);
โดยเราก าหนดให t1, t2, และ t5 เปน Binary tree ทไมมขอมลใด ๆ อยเลย กลาวคอ root
ของ Binary tree ทงสามมคาเปน null สวน t3, t4, และ t6 นนเราก าหนดใหมขอมลเปน 3, 4, และ 6 ตามล าดบ หลงจากนนเรากท าการเชอม node ตาง ๆ เหลานเขาดวยกนผานทางการเรยกใช makeTree() ภาพท 6.4 แสดงถง Binary tree ทเกดข นจากการสรางดวยขอมลตวอยางทกลาวถง
บทท 6 Binary Tree
157
ภาพท 6.4 Binary tree จากการสรางดวยขอมลตวอยาง (X หมายถง null)
ถาเราตองการทจะแสดงขอมลของ Binary tree ทเราไดสรางข นออกทางหนาจอ เรากใชค าสง
t1.printBinaryTree();
ซงกจะท าใหเราไดผลลพธดงน Items in tree: 4 6 5 2 3 1
และถาเราใชค าสง t2.printBinaryTree(); เรากจะไดผลลพธเปน
Items in tree: 4 6 5 2
ถาเราตองการทจะหาขนาด (size) ของ Binary tree เรากสามารถท าไดดวยการเขยน code ขนมานบจ านวนของ node ทมอยใน Binary tree ซงกไมยาก โดยภายใน class BinaryTree เรากเขยน method size() ดวยการเรยกใช size() ทมอยใน class BinaryNode ดงน public int size() {
return root.size(root);
}
สวนใน class BinaryNode เรากเขยน code ดงน public int size(BinaryNode<T> t) {
if(t == null)
return 0;
else
return size(t.left) + size(t.right) + 1;
}
ใน method size() ของ BinaryNode เราใชวธการของ Recursion เขามาชวยทงนเพราะเรารวา ขนาดของ Binary tree กคอขนาดของ Binary tree ทางดานซาย บวกกบขนาดของ Binary tree ทางดานขวา บวกกบตวมนเอง (ซงกคอ 1) และเรากรอกวาในการหา base case ของการนบจ านวน node นนเราตองตรวจสอบกบ null เพราะฉะนนทกครงทการเขาหา Binary tree ของเราเจอ null เรากสงคา 0 กลบท าใหการนบจ านวน node ของเราเปนการนบทถกตองเสมอ
root
1
2
5
3
6
4
Binary Tree บทท 6
158
อกส งหนงทเราอาจตองการหากคอ ความสงของ Binary tree (height) ซงวธการหากคลาย ๆ กบการหาขนาดของ Binary tree จะตางกนกตรงทเราตองสงคา -1 กลบในกรณของ base case ทงนกเพราะวาเรานบ node ทเปน root อยในระดบ 0 และเนองจากวา root ทอยใน Binary tree อาจมลกทงซายและขวา ดงนนเราจงจ าเปนทจะตองหาคาสงสดของลกทงสอง บวกกบ 1 ซงเปนคาของตว node root เอง ลองมาด code ของการหาความสงของ Binary tree ( height() ตวแรกอยใน class BinaryTree และ height() ตวทสองอยใน class BinaryNode public int height() {
return root.height(root);
}
public int height(BinaryNode<T> t) {
if(t == null)
return -1;
else
return Math.max(height(t.left), height(t.right)) + 1;
}
หลงจากทลองใช method ทงสองกบ Binary tree (t1) ทเราไดสรางขน ผลลพธทไดคอ Items in tree: 4 6 5 2 3 1
Size of Binary tree - t1 is 6
Height of Binary tree - t1 is 3
Binary tree ทเราไดกลาวถงเปน Binary tree แบบทวไปทไมมขอจ ากดหรอเงอนไขใด ๆ ในการน าขอมลเขา เราสามารถทจะน าขอมลเขาในลกษณะใดกได ทงนกตองข นอยกบผใชวาตองการสราง Binary tree ในลกษณะใด โดยสวนใหญแลวการน า Binary tree แบบนไปใชนนจะน าไปใชใน expression tree ซงเปนเรองของการออกแบบ compiler และการน าไปใชใน Huffman coding tree ซงเปนวธการบบอดขอมลแบบหนง 6.3 การเขาหา Binary tree การแสดงผลของขอมลทอยใน Binary tree ทเราไดเหนดานบนนเปนการแสดงผลดวยการเขาหาในรปแบบทเรยกวา Pre-order Traversal ซงเปนหนงในวธการเขาหา tree ทนยมใชกนพอสมควร อกสองวธทเหลอคอ In-order Traversal และ Post-order Traversal ในการเขาหา tree นนเมอเรามาถง node ทตองการแลว เราสามารถทจะท ากระบวนการตาง ๆ ทเราตองการไดเชน ดงขอมลของ node ออกพรอมกบแสดงผล หรอแมแตกระทงการลบ node นออกจาก tree 6.3.1 การเขาหาแบบ Pre-order การเขาหาแบบ Pre-order นนเราจะกระท ากระบวนการ (visiting) กบ node ทเราเจอกอน หลงจากนนเรากจะกระท ากบลกทงสองของ node ดวยวธการของ Recursion ดงขนตอนน
1. เรมกระบวนการกบ node (Visiting the node) 2. เดนทางเขาหาลกของ node ทางซาย (ดวยการเรยกตวเอง) 3. เดนทางเขาหาลกของ node ทางขวา (ดวยการเรยกตวเอง)
กระบวนการดงกลาวจะส นสดลงเมอ node ทก node ทอยใน tree ไดผานการเขาหาเรยบรอยแลว เรากลบมาด code ของการเขาแบบ Pre-order ทเราไดเขยนไวกอนหนานในการแสดงผลของ Binary tree public void preorderPrint() {
System.out.print(item + " ");
if(left != null)
left.preorderPrint();
if(right != null)
right.preorderPrint();
}
บทท 6 Binary Tree
159
จาก code ดานบนนจะเหนวาเราไดท ากระบวนการ "แสดงผล" ของ node ไปยงหนาจอกอน หลงจากนนเราจงเขาหาลกของ node นทางดานซาย หลงจากทลกของ node ทางดานซายไดรบการ "แสดงผล" แลวเรากเรมท าแบบเดยวกนกบลกของ node ทอยทางดานขวา สมมตวาเราใชการเขาหา tree แบบ Pre-order นกบ Binary tree ทเราสรางขนในภาพท 7.4 (ซงไดจ าลองมาใหดทางดานขวาของผลลพธ) พรอมกบใส code ส าหรบการ trace กระบวนการของ Pre-order Traversal เรากจะไดผลลพธดงน 1 Process child on the left of 1 2 Process child on the left of 2
4 Finish child on the left of 2 Process child on the right of 2 5 Process child on the left of 5 6 Finish child on the left of 5
Finish child on the right of 2 Finish child on the left of 1 Process child on the right of 1 3 Finish child on the right of 1 ผอานควรวเคราะหจากผลลพธทเหนกบโครงสรางของ Binary tree ทเราใชเปนตวอยาง เพอท าความเขาใจกบการเขาหาแบบ Pre-order ใหดย งข น 6.3.2 การเขาหาแบบ In-order การเขาหาแบบ In-order นเราจะกระท าการกบ node ระหวางการเขาหาลกของ node ทางซายและลกของ node ทางขวา ดงขนตอนน
1. เขาหา node ทางดานซาย (ดวยการเรยกตวเอง) 2. เรมกระบวนการกบ node (Visiting the node) 3. เขาหา node ทางดานขวา (ดวยการเรยกตวเอง)
ซง code ของการเขาหาแบบ In-order มดงน public void inorderPrint() {
if(left != null)
left.inorderPrint();
System.out.print(item + " ");
if(right != null)
right.inorderPrint();
}
และเมอเราลองใชการเขาหาแบบ In-order กบ Binary tree ตวเดยวกน เรากจะไดผลลพธ ดงน Process child on the left of 1
Process child on the left of 2
4
Finish child on the left of 2
2
Process child on the right of 2
Process child on the left of 5
6
Finish child on the left of 5
5
Finish child on the right of 2
Finish child on the left of 1
1
start node 1
3 2
5
6
4
start node
1
3 2
5
6
4
Binary Tree บทท 6
160
Process child on the right of 1
3
Finish child on the right of 1
6.3.3 การเขาหาแบบ Post-order การเขาหาแบบ Post-order นนเราจะท าการกบ node หลงจากทเราเสรจส นการเขาหาลกของ node ทงสองจนหมดแลว ดงขนตอนน
1. เดนทางเขาหาลกของ node ทางดานซาย (ดวยการเรยกตวเอง) 2. เดนทางเขาหาลกของ node ทางดานขวา (ดวยการเรยกตวเอง) 3. เรมกระบวนการกบ node (Visiting the node)
ดง code ทไดแสดงไวน public void postorderPrint() {
if(left != null)
left.postorderPrint();
if(right != null)
right.postorderPrint();
System.out.println(item);
}
และเมอใชกบ Binary tree ตวเดยวกน ผลลพธทไดคอ Process child on the left of 1
Process child on the left of 2
4
Finish child on the left of 2
Process child on the right of 2
Process child on the left of 5
6
Finish child on the left of 5
5
Finish child on the right of 2
2
Finish child on the left of 1
Process child on the right of 1
3
Finish child on the right of 1
1
หลาย ๆ คนอาจสงสยวาท าไมเราถงใช Recursion ในการเขยน code ส าหรบการเขาหาและอาจสงสยอกวา ไมใช Recursion ไดไหม ค าตอบกคอ ได เพราะโดยทวไปแลว compiler กใช Stack ในการจ าขนตอนการท างานของ Recursion เพราะฉะนนเรากสามารถทจะใช Stack มาเปนตวชวยในการเขยน code ส าหรบการเขาหา tree ได แตเนองจากวาการน าเอา Recursion เขามาใชท าใหการด code ทท างานจะท าไดงายขน ท าใหเหนภาพการท างานของ Algorithm อยางชดเจน เราคงจะจบเรองของการเขาหา tree ไวเพยงเทานกอน เราจะน าการเขาหาแบบตาง ๆ ซงรวมไปถงการเขาหาแบบ level-order มาใชกบ Binary Search Tree ตอไป
start node
1
3 2
5
6
4
บทท 6 Binary Tree
161
6.4 Binary Search Tree (BST) Binary tree ทเราจะมาท าความรจกเปนพเศษคอ Binary Search Tree ซงเปน Binary tree ทมขอก าหนดพเศษเฉพาะตวคอขอมลของ node ลกทอยทางซายของ node parent จะตองมคา นอยกวาคาของขอมลทอยใน node parent และ คาของขอมลทอยใน node ลกทอยทางขวาของ node parent จะมคามากกวาคาของขอมลทอยใน node parent ดงตวอยางของ tree ทแสดงใหเหนน
ภาพท 6.4 ตวอยาง Binary Search Tree ทมขอมลอย
ในการออกแบบ Binary Search tree นนเราไมจ าเปนทจะตองสราง class BinaryNode ขนมา
ใหม เราสามารถทจะใช BinaryNode ทเราไดสรางขนมากอนหนานไดเลย สวนทเราตองออกแบบ และสรางขนมาใหมคอ class BinarySearchTree ซงจะตองมกระบวนการน าขอมลเขาแบบใหม เนองจากขอก าหนดของ Binary Search tree ทมอย รวมไปถงกระบวนการอน ๆ ทจ าเปน เชน o การคนหาขอมล o การเขาหา BST
o การคนหา node ทมขอมลต าสด o การคนหา node ทมขอมลสงสด o การลบขอมลทก าหนดให o การลบ node ทมขอมลนอยทสด o การลบ node ทมขอมลมากทสด 6.4.1 การน าขอมลเขาส BST ในการน าขอมลเขาส BST นนเราตองตรวจสอบเงอนไขเสยกอนวาขอมลควรจะอยสวนไหนของ BST ซงตองตรวจสอบดวยกนสามเงอนไข คอ
1. BST ยงไมมขอมลใด ๆ อยเลย (empty) 2. ขอมลทตองน าเขานอยกวา node ณ ต าแหนงทท าการตรวจสอบ 3. ขอมลทตองน าเขามากกวา node ณ ต าแหนงทท าการตรวจสอบ
และอกเงอนไขหนงทเราอาจตองท า ถาเรากลววาขอมลทน าเขามอยใน BST แลว ซงเรากเพยงแตฟองผใชวาขอมลมอยใน BST เทานนเอง เรามาลองด code ของการน าขอมลเขากน public void insert(T item) {
root = insert(item, root);
}
53
72 30
14 39 61 84
9 23 34 47 79
Binary Tree บทท 6
162
private BinaryNode<T> insert(T item, BinaryNode<T> node) {
if(node == null)
node = new BinaryNode<T>(item);
else if(item.compareTo(node.item) < 0)
node.left = insert(item, node.left);
else if(item.compareTo(node.item) > 0)
node.right = insert(item, node.right);
else
;//item is already in tree!
return node;
}
เราใช Recursion ในการเขยน code กเพอทจะใหการด code นนท าไดงายขน ตามทเราไดพดไวในเรองของการน าขอมลเขาตามเงอนไข กลาวคอ ถา BST ไมมขอมลเรากเรยกใช
constructor ของ BinaryNode ถามขอมลอยกอนแลว และขอมลทตองการน าเขามคานอยกวาขอมลของ node ทเราตรวจสอบอยเรากท าการน าขอมลเขาทางดายซาย แตถามากกวาเรากน าขอมลเขาทางดานขวา ส าหรบการเขยน code ในรปแบบทไมใช Recursion นนเรากท าได ดงน //insert item into BST without using recursion
public void insert(T item) {
BinaryNode<T> node = new BinaryNode<T>(item);
//BST is empty
if(root == null)
root = node;
//at least there's one node in BST
else {
BinaryNode<T> walk = root;
BinaryNode<T> parent = new BinaryNode<T>();
//locate position for new node
while(walk != null) {
parent = walk;
if((node.item).compareTo(walk.item) < 0)
walk = walk.left; //must be in the left
else
walk = walk.right;//must be in the right
}
//found location; connect new node to this node
if((node.item).compareTo(parent.item) < 0)
parent.left = node;
else
parent.right = node;
}
}
การ insert node เขาส BST นนเราจ าเปนทจะตองตรวจสอบดวา คาของ node ทจะน ามาใสนน มากหรอนอยกวาคาของ node ทมอยแลวใน tree ถานอยกวาเรากตองใส node นทางดานซาย ถามากกวาเรากใส node นทางดานขวา เชนเดยวกนกบทเราท าการน าขอมลเขาดวยการใช
Recursion เรมตนดวยการสราง node ดวย object ทก าหนดไว BinaryNode<T> node = new BinaryNode<T>(item);
หลงจากนนก ตรวจสอบดวานเปนครงแรกทน าขอมลใสใน BST หรอไม ถาใช เรากเชอม node
root กบ node ใหมน แตถาไมใช (ม node อย) เรากตองหาต าแหนงทเหมาะสมของ node ใหมใน BST ของเรา
บทท 6 Binary Tree
163
if(root == null)
root = node;
//at least there's one node in BST
else {
BinaryNode<T> walk = root;
BinaryNode<T> parent = new BinaryNode<T>();
//locate position for new node
while(walk != null) {
parent = walk;
if((node.item).compareTo(walk.item) < 0)
walk = walk.left; //go left
else
walk = walk.right; //go right
}
}
เรมดวยการก าหนดให node walk ชไปท root เพอเอาไวใชส าหรบการเขาหา BST เราไมสามารถทจะใช root โดยตรงไดเพราะวา ในการเดนเขาหา BST นน เราเปลยนต าแหนงของ node ไปเรอย ๆ ซงถาใช root เปนตวเดน เรากไมสามารถน า BST กลบคนมาได เราใช node parent เปนตวเชอม node ใหมเขากบ BST ของเราเพราะฉะนน เราจ าเปนทจะตองจ าคาของ node walk ดวยการก าหนดให parent มคาเทากบ walk
เราท าการเปรยบเทยบคาของ item ท node walk ชอย กบคาของ item ของ node ใหม ถาคา item ของ node ใหม นอยกวา คาของ item ของ node walk เรากจะเดนไปทางซายจนกวาเราจะไปไมได (เทากบ null) แตถาคาของ node ใหมไมนอยกวาเรากจะเดนไปทางขวา จนไปไมได (เทากบ null เชนกน) ถาเราไปไมไดแลว ต าแหนงนจะเปนต าแหนงท เราตองเชอม node ใหมเขากบ BST ของเรา แตกอนทเราจะเชอม node ใหมเขาส BST เราตองตรวจดวาควรจะเชอม node ทางดานซาย หรอ ทางดานขวา //found location; connect new node to this node
if((node.item).compareTo(parent.item) < 0)
parent.left = node;
else
parent.right = node;
}
หลงจากทขอมลไดถก insert เขาส BST เปนทเรยบรอยแลว เรากสามารถทจะกระท ากระบวนการตาง ๆ ทเราท าได เชน การคนหาขอมล การแสดงขอมลทงหมดทมอยใน tree การลบ node ใด node หนงออกจาก tree หรอแมแตกระทงการน า node ใหมเขาส tree 6.4.2 การคนหาขอมลใน BST การคนหาขอมลใน BST นนท าไดไมยาก มนคลาย ๆ กบการคนหาขอมลใน Linked-List ทเรา
ไดเคยท ามากอนหนาน จะตางกน ตรงทเราตองเลอกทางคนหา วาจะเปนทางซาย หรอ ทางขวา ถาขอมลทตองการคนหามคานอยกวาขอมลทอยใน node ทท าการเปรยบเทยบ เรากคนไปทางซายเรอย ๆ ถาเจอเรากหยด แตถาไมเจอแสดงวา ขอมลนไมมอยใน BST เชนเดยวกนถาขอมลมากกวา หรอ เทากบขอมลของ node ทท าการเปรยบเทยบอย เรากคนไปทางขวาจนกวาจะเจอ ถาไปจนหมด node แลวไมเจอกแสดงวา ไมม node นในBST //search BST for a given data
public boolean search(T item) {
return search(item, root);
}
Binary Tree บทท 6
164
//internal search() for BST
private boolean search(T item, BinaryNode<T> node) {
while(node != null) {
if(item.compareTo(node.item) < 0)
node = node.left;
else if(item.compareTo(node.item) > 0)
node = node.right;
else
return true; //found item
}
return false; //no item found
}
การสงคากลบออกไปจาก method ของการคนหาอาจเปนการสงคาของขอมลทอยใน node นนออกไป หรอสงคา true เพอบอกวาขอมลมอยใน BST หรอ false เพอบอกวาไมมขอมลอยกได
ทงนกข นอยกบการใชงานของแตละคน ในทนเราจะใชการสงคา true หรอ false เราเรมตนดวยการเดนเขาหา BST ดวยการใช while loop พรอมกบท าการเปรยบเทยบขอมลของ node ทเราเจอกบขอมลทตองการคนหา ถาขอมลทตองการคนหามคานอยกวาขอมล ณ node นน ๆ เรากเดนทางเขาหาลกของ node ทางดานซาย แตถามากกวาเรากเดนเขาหาลกของ node นนทางดานขวา จนกวาจะเจอ หรอจนกวาเราจะเขาหา node ทมอยใน BST จนหมด ซงหมายถงการส นสดการคนหาทไมประสพผลส าเรจ
เราจะมาทดลองท าการน าขอมลเขาส BST พรอมทงแสดงขอมลทงหมดดวยการเขาทงสามแบบ (Pre-order, In-order, และ Post-order) ทเราไดพดถงกอนหนาน รวมไปถงการคนหาขอมลภายใน BST ดวย เราจะใชขอมลดานลางนเปนขอมลตวอยาง (ขอมลจากภาพท 6.4) 53 30 72 14 39 61 84 9 23 34 47 79
เราจะใชโปรแกรม BinarySearchTreeTest.java เปนโปรแกรมทดสอบ
1: /**
2: Testing module for binary search tree
3: */
4:
5: class BinarySearchTreeTest {
6: public static void main(String[] args) {
7: BinarySearchTree<Integer> t = new BinarySearchTree<Integer>();
8:
9: t.insert(53);
10: t.insert(30);
11: t.insert(72);
12: t.insert(14);
13: t.insert(39);
14: t.insert(61);
15: t.insert(84);
16: t.insert(9);
17: t.insert(23);
18: t.insert(34);
19: t.insert(47);
20: t.insert(79);
21:
22: System.out.println("Pre-order Traversal");
23: t.preOrderPrint();
24:
25: System.out.println("In-order Traversal");
26: t.inOrderPrint();
27:
28: System.out.println("Post-order Traversal");
29: t.postOrderPrint();
30:
31: Integer searchValue1 = new Integer(14);
32: if(t.search(searchValue1))
33: System.out.println("Found " + searchValue1);
34: else
35: System.out.println(searchValue1 + " Not found!");
36:
37: Integer searchValue2 = new Integer(66);
38: if(t.search(searchValue2))
บทท 6 Binary Tree
165
39: System.out.println("Found " + searchValue2);
40: else
41: System.out.println(searchValue2 + " Not found!");
42: }
43: }
ผลลพธทเราไดคอ Pre-order Traversal
Items in tree: 53 30 14 9 23 39 34 47 72 61 84 79
In-order Traversal
Items in tree: 9 14 23 30 34 39 47 53 61 72 79 84
Post-order Traversal
Items in tree: 9 23 14 34 47 39 30 61 79 84 72 53
Found 14
66 Not found!
ผอานควรสงเกตถงผลลพธทไดจากการเขาหา BST ทงสามแบบ โดยเฉพาะ การเขาหาแบบ In-order ทท าใหการแสดงผลขอมลทอยใน BST เปนการแสดงผลทเรมตนจากขอมลทนอยทสดไปหาขอมลทมากทสด 6.4.3 การเขาหาแบบ Level-Order
การเขาหาขอมลใน BST (หรอ tree แบบอน ๆ) ทเรยกวา level-order traversal นนจะท าการเขาหา node ทกตวในแตละชนกอนทจะเลอนระดบลงไป โดยเรมตนทระดบ 0 จนถงระดบลางสด ดงแสดงในภาพท 6.5
ภาพท 6.5 ทศทางการเขาหา BST แบบ Level-Order Traversal
เนองจากวาการเขาหาแบบนเปนการเขาหา node ลกทงสองของ BST (ถาม) ดงนนเราจงตองใช queue มาเปนตวชวยในการเกบต าแหนงของลกทงสองไว เพอเปน node เรมตนในการเขาหา node อน ๆ ในระดบทต าลงไป และเพอใหเปนการงายตอการท างานเราจะก าหนด class Queue ใหเปน class ทอยภายใน class BinarySearchTree โดยเราจะใช class LinkedList ของ Java เปนโครงสรางหลกของ Queue ซงม code ในการท างานทงหมดดงน
//internal queue for level-order print
class Queue<T> {
//use Java's LinkedList to keep track of nodes
private LinkedList<T> list = new LinkedList<T>();
//put node into queue
public void put(T object) {
list.addFirst(object);
}
53
72 30
14 39 61 84
9 23 34 47 79
Binary Tree บทท 6
166
//get node from queue
public T get() {
if(isEmpty())
return null;
return list.removeLast();
}
//empty?
public boolean isEmpty() {
return list.isEmpty();
}
}
ส าหรบ code ของ levelOrderPrint() นนเราก าหนดใหมโครงสรางดงน //level-order print
public void levelOrderPrint() {
//queue to keep track of nodes
Queue<BinaryNode<T>> q = new Queue<BinaryNode<T>>();
BinaryNode<T> current = root;//points to root of tree
//loop until all nodes have been processed
while(current != null) {
System.out.print(current.item + " ");
if(current.left != null) //add left child to queue
q.put(current.left);
if(current.right != null)//add right child to queue
q.put(current.right);
//get next node in queue
if(!q.isEmpty())
current = q.get();
else
current = null;
}
System.out.println();
}
การท างานของ levelOrderPrint() เรมดวยการสราง queue ทไมมขอมลใด ๆ และก าหนดให current เปน node ทช ไปยง root ของ tree หลงจากนนเราจะเขาหา node ทกตวใน tree ซงหลงจากทเราแสดงขอมลทอยใน current ไปยงหนาจอแลว (node แรกสดใน tree) เรากจะน า node ลกทอยทางซายและขวาของ current (ถาม) เขาส queue เพราะฉะนน node แรกสดท
อยใน queue จะเปน node ทอยทางซาย ถาเราใช tree จากภาพท 6.5 node นมคาเปน 30 และ node ทมคาเปน 72 จะเปน node ทอยถดไป ดงนนเมอเราดงเอาขอมลออกจาก queue เรากจะได node 30 เปน node ถดไปของการประมวลผล และเรากจะน าเอาลกทงสองของ node 30 เขาส queue (node 14 และ node 39) หลงจากนนเรากจะดงเอา node ทอยถดไปใน queue ออกซงกคอ node 72 พรอมกบการเอาลกทงสองของ node 72 เขาส queue ซงกคอ node 61 และ node 84 เราจะท ากระบวนแบบนไปจนกวา node ทกตวจะไดรบการประมวลผล จงออกจาก loop ซงเปนการจบกระบวนการทงหมดของ levelOrderPrint() และเมอเราได
ทดสอบดวยขอมลทอยใน tree จากภาพท 6.5 ผลลพธทเราไดคอ Level-order Traversal
53 30 72 14 39 61 84 9 23 34 47 79
การเขาหา tree แบบนมช ออกอยางหนงวา Breadth-First Traversal ซงเราจะกลบมาพดถงการเขาหาแบบนอกครงในเรองของ Graph 6.4.4 การคนหา node ทมขอมลนอยทสด การคนหา node ทมขอมลนอยทสดเปนการคนหาทงายพอสมควร เนองจากวาเราแทบจะไมตองเขยน code ใหซบซอนมากมายอะไร เพยงแตเดนเขา BST ไปทางซายจนกวา node ลกของ node ซายสดทเราเจอมคาเทากบ null เรากยตการเขาหาพรอมกบสงคาของขอมล ณ node กลบออกไป ดง code ทแสดงใหดน
บทท 6 Binary Tree
167
//search for node that has smallest value
public T findMin() {
return findMin(root);
}
//internal method for findMin()
public T findMin(BinaryNode<T> node) {
if(node != null) {
while(node.left != null)
node = node.left;
}
return node == null ? null : node.item;
}
6.4.5 การคนหา node ทมขอมลมากทสด
เชนเดยวกนกบการคนหา node ทมขอมลนอยทสดทเราไดแสดงใหดกอนหนาน เราไมตองท าอะไรมาก เพยงแตเดนเขาหา BST ไปทางขวาจนกวา node ลกของ node ทอยขวาสดมคาเปน null และเมอเจอเรากสงคา ณ node กลบออกไป ดง code ทแสดงใหดน //search for node that has biggest value
public T findMax() {
return findMax(root);
}
//internal method for findMax()
public T findMax(BinaryNode<T> node) {
if(node != null) {
while(node.right != null)
node = node.right;
}
return node == null ? null : node.item;
}
หลงจากทลองใช method ทงสองหาคาของ node ทนอยทสด และมากทสดใน BST ตวอยาง ผลลพธทเราได คอ Smallest node: 9
Biggest node: 84
6.4.6 การลบ node ออกจาก tree กระบวนการทเราจะดตอไป คอ การลบ node ออกจาก BST ซงการลบ node ออกจาก tree นนมขนตอนการท างาน ทยงยากพอสมควร เราจะตองค านงถงลกษณะของ node วาเปน node ในลกษณะใด เชน 1. เปน node ทไมมลกหลานอยเลย (leaf node) ในกรณท BST ไมมลกหลานอยเลย ส งทเราตองท ากคอ ก าหนดให parent ของ node ท
ตองการลบชไปท null (node ทตองการลบ = null) ดงแสดงในภาพท 6.6
Binary Tree บทท 6
168
(กอนลบ) (หลงลบ)
ภาพท 6.6 การลบ leaf node (node 9 และ node 34)
2. เปน node ทมลกอยเพยง node เดยว ถา node มลกเพยงแค node เดยวเรากก าหนดให parent ของ node ทตองการลบมคา
เทากบ ลกของ node น ดงแสดงในภาพท 6.7
(กอนลบ) (หลงลบ)
ภาพท 6.7 การลบ node (84) ทม node ลกเพยง node เดยว (79)
3. เปน node ทมลกอยครบทงค วธการลบ node ทมลกอยทงทางดานซาย และทางดานขวานน เราสามารถท าไดสองวธคอ
หา node ทมคามากทสดทางดานซายของ node ทตองการลบออกมาแทนท หรอหา node ทมคานอยทสดทางดานขวามาแทนท node ทตองการลบออก ไมวาจะใชวธไหน เรากยงคงรกษารปแบบและขอก าหนดของ BST ไว (ผอานควรวเคราะหดวยตวเองวาประโยคทกลาวนเปนจรง)
30
14 39
23 47 null null
30
14 39
23 47 9 34
72
61 84
79
72
61 79
บทท 6 Binary Tree
169
ภาพท 6.8 การลบ node ทม ลกอยทง 2 node (node 14 และ node 39)
สมมตวาเราตองการลบ node 30 ออกจาก tree ดวยการหา node ทมคามากทสดทาง
ดานซายมาแทนเรากจะได tree ดงทเหนน
ภาพท 6.9 การแทนท node ทถกลบออก (30) ดวย node ทางซาย (23)
แตถาเราใชวธแทนทดวย node ทมคานอยทสดทางดานขวาเรากจะได BST ดงน
ภาพท 6.10 การแทนท node ทถกลบออก (30) ดวย node ทางขวา (34)
30
14 39
23 47 9 34
23
14 39
47 9 34
34
14 39
23 47 9
Binary Tree บทท 6
170
6.4.7 การลบ node ทมคานอยทสด กอนทเราจะออกแบบ code ส าหรบการลบ node ออกจาก BST ตามเงอนไขทพดไวเรามาด การลบ node ทมคานอยทสดใน BST กนกอน เพราะเปนการลบทงายทสด และเรากจะน าเอาการลบ node ทมคานอยทสดนมาใชกบการลบ node ทมขอก าหนดตามเงอนไขทไดก าหนดไว //remove smallest node
public void removeMin() {
root = removeMin(root);
}
//internal method to remove smallest node
private BinaryNode<T> removeMin(BinaryNode<T> node) {
if(node == null) {
System.out.println("ERROR! BST is empty.");
return null;
}
else if(node.left != null) {
node.left = removeMin(node.left);
return node;
}
else {
return node.right;
}
}
เนองจากวา node ทมคานอยทสดนนจะอยทางดานซายสดของ BST และเปน node ทไมมลกอยทางดานซาย ดงนนการลบ node กเปนเพยงการเดนเขาหา node ทอยซายสดพรอมกบการจดจ า node ทไดเดนผานมาแลวใน BST ขนตอนในการลบ node ทมคานอยทสดเรมตนดวยการตรวจสอบวา BST ม node อยหรอไม ถามเรากตรวจสอบอกวาลกของ node ทอยทางดานซายเปน null หรอไม ถาไมเปนเรากเรยก removeMin() ดวย node ทอยทางดานซายนไปจนกวา node.left หรอลกของ node ทอยทางซายเปน null จาก code ทเหนดานบน ถาการท างานของ code มาถงประโยค else สดทายเรารทนทวาเราไดมาถง node ทมคานอยทสด เราจงสงคาของ parent ของ node ทมคานอยทสดนกลบออกไป ภาพท 6.11 และ 6.12 แสดงถง BST 2 ตวทม node ทมคานอยทสดทอยทางซาย และทอยทางขวา
ภาพท 6.11 ถาลบ node 9 node ทแทนคอ null ภาพท 6.12 ถาลบ node 14 node ทแทนคอ 23
การสงคากลบออกไปจาก removeMin() นนเราตองค านงถงกรณทงสองทไดกลาวถง สมมตวาเราลบ node 9 ในภาพท 6.11 ออกสงทเราตองก าหนดให left ของ node 14 กคอ null แตถาเราลบ node 14 ในภาพท 6.12 ออกสงทเราตองก าหนดให left ของ node 30 คอ node 23 ดงนนการสงคา node.right ในบรรทดสดทายจงเปนการเชอม node ทครอบคลมถงกรณทงสองไดเปนอยางด
30
14 39
23 47 34 null
30
23 39
47 9 34 null
บทท 6 Binary Tree
171
หลงจากททดสอบการลบ node ทมคานอยทสดทงสองกรณ (พรอมทงเพม code ส าหรบการ trace) เรากจะไดผลลพธดงน ผลลพธอนแรกเปนการลบ node 9 ในภาพท 6.11 สวนผลลพธทสองเปนการลบ node ในภาพท 6.12 (ขอมลทใชจรงตามภาพท 6.4) Smallest node: 9
Biggest node: 84
node = 53
node = 30
node = 14
node to be deleted = 9
node.left = null
node.right = null
returning node = 14
returning node = 30
returning node = 53
Items in tree: 14 23 30 34 39 47 53 61 72 79 84
Smallest node: 14
Biggest node: 84
node = 53
node = 30
node to be deleted = 14
node.left = null
node.right = BinaryNode@108786b returning node = 30
returning node = 53
Items in tree: 23 30 34 39 47 53 61 72 79 84
ผอานควรตรวจสอบถงผลลพธทไดทงสองเพอใหเขาใจถงการท างานของ removeMin() ไดดย งข น 6.4.8 การลบ node ทก าหนดใหออกจาก BST ในการลบ node ใด ๆ ออกจาก BST เราจ าเปนทจะตองค านงถงต าแหนงของ node ทเราตองการลบออก ทงนกเพราะวาเราจ าเปนทจะตองโยกยาย node อน ๆ ทเกยวของใหอยในต าแหนงทเหมาะสมเพอทจะรกษาคณสมบตของ BST ไว ดงกรณตาง ๆ ทงสามทไดกลาวไว กอนหนาน //remove a given node
public void remove(T item) {
root = remove(item, root);
}
//internal method to remove a given node
private BinaryNode<T> remove(T item, BinaryNode<T> node) {
if(node == null) {
System.out.println("ERROR! BST is empty");
System.exit(1);
}
if(item.compareTo(node.item) < 0) {
node.left = remove(item, node.left);
}
else if(item.compareTo(node.item) > 0) {
node.right = remove(item, node.right);
}
else if(node.left != null && node.right != null) {
node.item = findMin(node.right);
node.right = removeMin(node.right);
}
else
node = (node.left != null) ? node.left : node.right;
return node;
}
สงทเราตองท าส าหรบการลบ node คอการเดนเขาหา node ทมขอมลตามทเราตองการลบออก โดยเราจะเรมดวยการตรวจสอบวา BST นนมขอมลหรอไม ถาไมมการลบกยต แตถามเรากท าการคนหาขอมลทตองการลบออกทางดานซาย หรอทางดานขวาดวยวธการของ Recursion
Binary Tree บทท 6
172
ตามเงอนไขทก าหนดไว ถาเราเจอ node ทมลกอยทงสองดาน เรากก าหนดให node นมคาเทากบ node ทนอยทสดทอยทางขวาของ node นพรอมทงลบ node ทนอยทสดนออก แตถา node มลกอยเพยงตวเดยว เราตองดวาลกตวนเอยทางซายหรอไม ถาอยทางซายเรากก าหนดให node นเทากบ node ลกทางดานซายน แตถาไมใชเรากก าหนดให node นมคาเปน node ลกทางดานขวา หลงจากททดสอบดวยการลบ node 30 ออกจาก BST ในภาพท 6.4 เราไดผลลพธดงน node: 53 left node = 30
Found node to delete: 30
Find minimum node and set 30 to this node: 34
Remove minimum node
Return from removeMin(), set node.right to 39
return from node: 53
Items in tree: 9 14 23 34 39 47 53 61 72 79 84
เราเลอกทจะลบ node 30 กเพราะวาเราตองการทจะแสดงถงการลบ node ทมลกอยทงทางดานซายและทางดานขวา ภาพท 6.13 และ 6.14 แสดงถง BST กอนและหลงจากการลบ node 30
ภาพท 6.13 BST กอนการลบ node 30 ภาพท 6.14 BST หลงจากการลบ node 30
ขนตอนการท างานในสวนของการคดเลอก node ทจะมาแทนท node 30 นนเราใชการเลอก node ทมคาทนอยทสดทอยทางดานขวาของ node 30 ซงกคอ node 34 ดงนน BST ทเราได หลงจากการลบ node 30 แลวจงมหนาตาดงทเหน หากผอานตองการทจะใชการคดเลอกทเอา node ทมคามากทสดทางดานซาย (node 23 ในภาพ) มาแทนท node 30 กยอมทจะท าได เราไดรวบรวม code ทงหมดของ Binary Search Tree มาแสดงใหดอกครงหนง
1: /**
2: Binary Search Tree implementation
3: */
4:
5: import java.util.LinkedList;
6:
7: class BinarySearchTree<T extends Comparable<? super T>> {
8: protected BinaryNode<T> root;
9:
10: public BinarySearchTree() {
11: root = null;
12: }
13:
14: public void insert(T item) {
3. เปลยนคา node 30 ใหเปน 34
2. หา node ทนอยทสด (34)
1. เจอ node 30 ทตองการลบ
53
30
14 39
9 23 34 47
53
34
14 39
9 23 47
บทท 6 Binary Tree
173
15: root = insert(item, root);
16: }
17:
18: //insert item into BST (recursive version)
19: private BinaryNode<T> insert(T item, BinaryNode<T> node) {
20: if(node == null)
21: node = new BinaryNode<T>(item);
22: else if(item.compareTo(node.item) < 0)
23: node.left = insert(item, node.left);
24: else if(item.compareTo(node.item) > 0)
25: node.right = insert(item, node.right);
26: else
27: ;//item is already in tree!
28:
29: return node;
30: }
31:
32: //search BST for a given data
33: public boolean search(T item) {
34: return search(item, root);
35: }
36:
37: //internal search() for BST
38: private boolean search(T item, BinaryNode<T> node) {
39: while(node != null) {
40: if(item.compareTo(node.item) < 0)
41: node = node.left;
42: else if(item.compareTo(node.item) > 0)
43: node = node.right;
44: else
45: return true; //found item
46: }
47: return false; //no item found
48: }
49:
50: //search for node that has smallest value
51: public T findMin() {
52: return findMin(root);
53: }
54:
55: //internal method for findMin()
56: public T findMin(BinaryNode<T> node) {
57: if(node != null) {
58: while(node.left != null)
59: node = node.left;
60: }
61: return node == null ? null : node.item;
62: }
63:
64: //search for node that has biggest value
65: public T findMax() {
66: return findMax(root);
67: }
68:
69: //internal method for findMax()
70: public T findMax(BinaryNode<T> node) {
71: if(node != null) {
72: while(node.right != null)
73: node = node.right;
74: }
75: return node == null ? null : node.item;
76: }
77:
78: //remove smallest node
79: public void removeMin() {
80: root = removeMin(root);
81: }
82:
83: //internal method to remove smallest node
84: private BinaryNode<T> removeMin(BinaryNode<T> node) {
85: if(node == null) {
86: System.out.println("ERROR! BST is empty.");
87: return null;
88: }
Binary Tree บทท 6
174
89: else if(node.left != null) {
90: node.left = removeMin(node.left);
91: return node;
92: }
93: else {
94: return node.right;
95: }
96: }
97:
98: //remove a given node
99: public void remove(T item) {
100: root = remove(item, root);
101: }
102:
103: //internal method to remove a given node
104: private BinaryNode<T> remove(T item, BinaryNode<T> node) {
105: if(node == null) {
106: System.out.println("ERROR! BST is empty");
107: System.exit(1);
108: }
109: if(item.compareTo(node.item) < 0) {
110: node.left = remove(item, node.left);
111: }
112: else if(item.compareTo(node.item) > 0) {
113: node.right = remove(item, node.right);
114: }
115: else if(node.left != null && node.right != null) {
116: node.item = findMin(node.right);
117: node.right = removeMin(node.right);
118: }
119: else
120: node = (node.left != null) ? node.left : node.right;
121:
122: return node;
123: }
124:
125:
126: public void preOrderPrint() {
127: System.out.print("Items in tree: ");
128: if(root != null)
129: root.preorderPrint();
130: else
131: System.err.println("Sorry! Tree is empty.");
132: System.out.println();
133: }
134:
135: public void inOrderPrint() {
136: System.out.print("Items in tree: ");
137: if(root != null)
138: root.inorderPrint();
139: else
140: System.err.println("Sorry! Tree is empty.");
141: System.out.println();
142: }
143:
144: public void postOrderPrint() {
145: System.out.print("Items in tree: ");
146: if(root != null)
147: root.postorderPrint();
148: else
149: System.err.println("Sorry! Tree is empty.");
150: System.out.println();
151: }
152:
153: //level-order print
154: public void levelOrderPrint() {
155: //queue to keep track of nodes
156: Queue<BinaryNode<T>> q = new Queue<BinaryNode<T>>();
157: BinaryNode<T> current = root;//points to root
158:
159: //loop until all nodes have been processed
160: while(current != null) {
161: System.out.print(current.item + " ");
162: if(current.left != null) //add left child to queue
บทท 6 Binary Tree
175
163: q.put(current.left);
164: if(current.right != null) //add right child to queue
165: q.put(current.right);
166:
167: //get next node in queue
168: if(!q.isEmpty())
169: current = q.get();
170: else
171: current = null;
172: }
173: System.out.println();
174: }
175: }
176:
177: //internal queue for level-order print
178: class Queue<T> {
179: //use Java's LinkedList to keep track of nodes
180: private LinkedList<T> list = new LinkedList<T>();
181:
182: //put node into queue
183: public void put(T object) {
184: list.addFirst(object);
185: }
186:
187: //get node from queue
188: public T get() {
189: if(isEmpty())
190: return null;
191: return list.removeLast();
192: }
193:
194: //empty?
195: public boolean isEmpty() {
196: return list.isEmpty();
197: }
198: }
สรป เราไดท าความรจกกบโครงสรางของ Binary tree และกระบวนการตาง ๆ ทจ าเปนในการจดการกบขอมลทมอยใน Binary tree แบบตาง ๆ เชน การน าขอมลเขา การคนหาขอมล การดงขอมลออก การหาความสง เราไดพดถงโครงสรางของ Binary Tree ชนดพเศษคอ Binary Search
Tree โดยรวมแลวเราไดพดถง โครงสรางของ Binary tree โดยทวไป การเขาหา Binary tree แบบตาง ๆ เชน pre-order, in-order, post-order, และ level-
order โครงสรางของ Binary Search Tree การคนหาขอมลใน Tree
การน าขอมลเขา/ออก จาก Binary Search Tree แบบฝกหด 1. จงแสดงถงผลลพธของการเขาหา tree จากภาพดวย pre-order, in-order, และ post-
order
Binary Tree บทท 6
176
2. จากภาพในขอหนง ก. และ ข. จงวาดภาพของ tree ใหมถาเปลยนโครงสรางของ tree ดวย
การน าเอา BST มาใช 3. จงเขยน method ทท าหนาทนบจ านวนของ node ทเปน leaf node ทงหมดทอยใน
Binary Tree พรอมทงเขยนโปรแกรมทดสอบ 4. จงเขยน method ทท าหนาทนบจ านวนของ node ทก node ใน Binary Tree ทมลกเพยง
หนงตว พรอมทงเขยนโปรแกรมทดสอบ 5. จงเขยน method ทท าหนาทนบจ านวนของ node ทก node ใน Binary Tree ทมลกครบ
ทงค พรอมทงเขยนโปรแกรมทดสอบ 6. จากโจทยในขอสาม ใหเปลยนจาก Binary Tree เปน Binary Search Tree
7. จงเขยน method ทท าหนาทในการสลบขอมลของ node ซายขวาดงทแสดงใหดเปนตวอยางจากภาพดานลางน
8. จงเขยน method ทเขาหา tree ตามล าดบชนของ tree เชนถาเราเขาหา tree ในขอ 7
ผลลพธทไดคอ 1 2 3 4 5 6 7 8 (ภาพทางซาย) หรอ 1 3 2 6 5 4 8 7 (ภาพทางขวา) ให เขยนโปรแกรมทดสอบ
1
3
2
4
7
5 6
8
1
5
3
6
2
4
8 9 7
(ก) (ข)
1
5
3
6
2
4
8 7
1
5
2
4
3
6
7 8
เปลยนเปน