breadth first search
Document Sample


Tree
ลักษณะทัวไป
่
1.
2. 5. 6.
3. 4. 7.
• ตัว โนด บนสุ ดจะเรี ยกว่าเป็ น ราก (root) ของ tree
่
• tree ส่ วนย่อย (มี โนด 2 เป็ น root) เรี ยกได้วาเป็ น subtree ของ tree
ใหญ่
• โนด 1 จะเป็ น บัพแม่ (parent) ของ โนด 2,5,6 ส่ วน โนด 2 เป็ น parent
ของ โนด 3,4 หรื อเรี ยกอีกอย่างว่า โนด 3,4 เป็ น บัพลูก (child) ของ โนด 2
• โนด 3 เป็ นบัพพีน้อง (sibling) กับ โนด 4
่
• ถ้ามีความสัมพันธ์แบบ parent ตั้งแต่หนึ่ งทอดขึ้นไป เราเรี ยกว่า บัพบน
(ancestor) เช่น โนด 1 เป็ น ancestor ของ โนด 7
• โนด ที่ไม่มีกิ่งออกไป เราเรี ยกว่า บัพใบ หรือ ใบ (leaf) เช่นในรู ป
leaf คือ โนด 3, 4, 5 และ 7
่
• เราจะสังเกตได้วา มีแค่ 1 เส้ นทาง (path) จาก root ไปยัง โนด แต่
ละ โนด เท่านั้น
• ความลึก (depth) ของ โนด n คือความยาวของ path จาก
root ถึง n ตัวอย่างเช่น depth ของ โนด เบอร์ 7 คือ 2
• ความสู ง (height) ของ โนด n คือความยาวของ path ที่ยาว
ที่สุดจาก n ถึง leaf ตัวอย่างเช่น height ของ โนด เบอร์ 7 คือ 0
และ height ของ โนด เบอร์ 1 คือ 2
• height ของ tree ก็คือ height ของ root นันเอง ถ้า tree
่
มีแค่ root เราให้ height เป็ น 0 และถ้า tree เป็ น empty
tree เราให้ height เป็ น -1
• height ของต้นไม้ใดๆ จะเท่ากับ height ของ subtree ที่สูง
ที่สุด บวกด้วย 1
• ระดับ (level) ของ โนด คือ ลาดับชั้นของโนดนั้น โดย child
ของ โนด หนึ่งๆจะมีระดับ1 ระดับมากกว่า parent ของมัน (root
ถือว่ามีระดับเป็ น 0)
ถ้าให้แต่ละโนด มีกี่กิ่งก็ได้
• เราไม่มีทางกาหนดจานวนกิ่งที่แน่นอนได้
• การเตรี ยมกิ่งไว้ล่วงหน้ามากๆก็เป็ นการเปลืองหน่วยความจา
• วิธีหนึ่งที่อาจแก้ปัญหานี้ได้คือ
1
ข้อมูล Link ไปยัง sibling ถัดไป
2 5 6
Link ไปยังลูกกิ่งแรก 3 4 7
(first child)
ลักษณะของต้นไม้จากรู ปแรกที่สร้างด้วยแนวคิดนี้
การเรี ยงดูสมาชิกภายในต้นไม้
• ก่อนลาดับ (preorder)
• ดูของจาก root โนด ที่เราเริ่ มพิจารณา แล้วจึงไปดูของใน
subtree โดยใน subtree ก็เริ่ มดูจาก root โนด เช่นเดียวกัน
ผลการเรี ยงสมาชิกใน โนด จากรู ป คือ 1,2,3,4,5,6,7
อันดับแรกที่ดู
1.
อันดับสองที่ดู เป็ น อันดับ4 ที่ดู เป็ น
subtree subtree
2. 5. 6.
ซึ่งภายในก็จะ
ซึ่งภายในก็จะ
เรี ยงดูแบบ
เรี ยงดูแบบ
preorder
preorder
3. 4. 7.
อันดับ3 ที่ดู
• หลังลาดับ (postorder)
– คือการเรี ยงดู subtree ทั้งหมด แล้วจึงมาดูของใน root ซึ่งภายใน subtree นั้น
้
ก็ตองมีการเรี ยงดูแบบเดียวกัน
– เพราะฉะนั้นถ้าเราเรี ยงสมาชิกใน tree ในรู ปที่แล้วแบบ postorder จะได้ผลลัพธ์
เป็ น 3,4,2,5,7,6,1
• ตามลาดับ (inorder)
– คือการเรี ยงสมาชิกโดยสมาชิกของ subtree ด้านซ้ายของ root จะถือว่าต้องมาก่อน
่ ้
root ส่ วนสมาชิกของ subtree ที่อยูดานขวาของ root จะถือว่ามาทีหลัง root
นอกจากนี้ส่วนข้างในตัว subtree ก็ใช้วธีการเรี ยงอย่างเดียวกัน
ิ
ั ่ ้
– ดังนั้นถ้าดูจากรู ป (ไม่นบ subtree ที่มี 5 เพราะไม่รู้จะจัดอยูขางไหนของ root) เรา
จะเรี ยงสมาชิกได้เป็ น 3,2,4,1,6,7
การค้นหาในแนวกว้าง (breadth-first search)
• วิธีการสามแบบแรกที่กล่าวมาข้างต้นนั้น เป็ นวิธีการค้นหาในแนวลึก
(depth-first search)
• ซึ่งถ้ามีการดู subtree ใดแล้วจะต้องตรวจสอบทั้ง subtree นั้น
ให้เสร็ จ จึงจะสารวจ root หรื อ subtree อื่นๆที่เป็ น sibling
ต่อไปได้
• breadth-first จะตรวจสอบทีละระดับของ tree โดยเริ่ มจาก
ระดับของ root ดังนั้น tree ในรู ปหน้าก่อนโน้นจะมีการเรี ยง
สมาชิกได้เป็ น 1,2,5,6,3,4,7
breadth-first implementation
• ตอนที่ดูโนดโนดหนึ่ง เราจะบันทึก child ของโนดนั้นลงในคิวที่
สร้างไว้สาหรับเก็บโนดในระดับถัดลงมา (next level queue)
เช่น ถ้าเรามี *
+ -
a * d e
b c
breadth-first implementation(2)
• เมื่อเราดู root เราจะบันทึก child โนด ของ root ไว้บน next level queue ดังนั้น ใน
ขั้นนึ้ next level queue มี + กับ –
• update ให้ this level queue = next level queue แล้ว เคลียร์ next level queue
• ั ู
สารวจ this level queue จะพบ + เป็ นตัวแรก ตอนนี้ให้ดูตวต้นไม้แล้วใส่ ลกของ +
ลงใน next level queue นันคือ ในตอนนี้ next level queue = a,*
่
• ู
สารวจ this level queue ต่อ จะพบ – เป็ นสมาชิกตัวต่อมา ใส่ ลกของ - ลงใน next
level queue นันคือ ในตอนนี้ next level queue = a,*,d,e
่
• ไม่มีสมาชิกใน this level queue แล้ว ดังนั้น update ให้ this level queue = next
level queue นันคือ this level queue = a,*,d,e
่
• ่ ้
เริ่ มเยียม this level queue ตั้งแต่ตนอีกครั้ง และทาซ้ าไปเรื่ อยๆ
ต้นไม้แบบทวิภาค (Binary Tree)
• แต่ละ โนด มีกิ่งออกไปได้มากที่สุดสองกิ่ง
• ดังนั้นอาจมีกิ่งเดียวในทุกระดับก็ได้ ซึ่งก็จะกลายเป็ น linked list
่
ไป หรื ออาจเรี ยกอีกอย่างได้วา skewed tree
full binary tree หรื อ perfectly
balanced tree
• เป็ นรู ปสามเหลี่ยมอย่างสมบูรณ์ ไม่ขาด leaf ใดๆในระดับของ leaf
ที่สูงที่สุด
ต้นไม้บริ บูรณ์ (complete tree)
• เต็มถึงระดับก่อน leaf ที่สูงที่สุดแต่ระดับของ leaf ที่สูงที่สุดอาจไม่
ั ้
เต็ม (แต่ยงมี leaf เติมใส่ ตนจากซ้ายไปขวา)
A
N E
T O X
้
ต้นไม้แบบเต็มต้นถือว่าเป็ นต้นไม้บริ บูรณ์แน่นอน แต่ตนไม้บริ บูรณ์ไม่จาเป็ นต้องเต็มต้น
ต้นไม้บริ บูรณ์ (2)
• ข้อสังเกตอีกอย่างคือ ถ้าเราเอาสมาชิกของต้นไม้บริ บูรณ์ใส่ ในอาร์ เรย์ โดยเรี ยงใส่
แบบตามแนวกว้าง (breadth-first)
่
– สมาชิกที่ตาแหน่ง i จะมีลูกซ้ายอยูที่ตาแหน่ง 2i+1
่
– และลูกขวาอยูที่ตาแหน่ง 2i+2
่
– ส่ วนตัว parent ของ i จะอยูที่ตาแหน่ง (i-1)/2 (ปั ดทศนิยมทิ้งไป)
A N E T O X
ลูกซ้ายของ E จะต้องมี index =2*2+1 =5 ซึ่ งก็คือ X
นันเอง ส่ วน parent ของ E ก็จะมี index = (2-1)/2 =
่
0 เมื่อปัดลง
two-tree
็
• จะต้องเป็ น empty tree หรื อไม่กมี non-leaf node ที่
ต้องมีสองกิ่งเท่านั้น
ทฤษฎีต่างๆของต้ นไม้ ทวิภาค
ถ้าเราให้
ั่
• leaves(t) แทนฟังก์ชนที่บอกจานวนใบของต้นไม้ t
• n(t) เป็ นจานวนโนดของ ต้นไม้ t
• height(t) เป็ นความสูงของต้นไม้ t
่
• leftsubtree(t) เป็ นต้นไม้ยอยด้านซ้ายของ t
่
• rightsubtree(t) เป็ นต้นไม้ยอยด้านขวาของ t
• max(a,b) เป็ นค่าที่มากที่สุดเมื่อเทียบ a กับ b
้ ่
สาหรับต้นไม้ทวิภาคที่ไม่ใช่ตนไม้วาง จะมีความสัมพันธ์
ั่
ระหว่างฟังก์ชนต่างๆดังนี้
n(t ) 1
leaves(t )
2.0
n(t ) 1
2 height ( t )
2.0
n (t ) 1
ถ้า t เป็ น two-tree แล้วละก็ leaves (t )
2.0
n (t ) 1
ถ้า leaves (t ) แล้วละก็ t เป็ น two-tree แน่นอน
2.0
ถ้า t เป็ นต้นไม้แบบเต็มต้น แล้วละก็ n (t ) 1 (t )
2height
2.0
n (t ) 1
ถ้า 2height (t )
แล้วละก็ t เป็ นต้นไม้แบบเต็มต้น
2.0
อย่าลืมว่าเราใช้ 2.0 เพราะฉะนั้นค่าจากสู ตรเหล่านี้ผมจะถือว่าเป็ นทศนิยมนะ
ั
เพราะจานวนเต็มจะใช้กบกฎข้อ 4 ไม่ได้
n(t ) 1
พิสูจน์ leaves(t )
2.0
base case คือเมื่อ t เป็ น ต้นไม้ที่มีแต่ราก
leaves (t ) 1
n(t) 1
1
2.0
ซึ่งเห็นชัดว่าทาให้สมการเป็ นจริ ง
inductive case คือ เมื่อ t เป็ นต้นไม้ที่สูง h
ให้
n(t ) 1
leaves(t )
2.0
n(t ) 1
สิ่ งทีต้องพิสูจน์ คือ เมื่อ t เป็ นต้นไม้ที่สูง h+1 แล้ว leaves(t )
่
2.0
leaves(t) leaves(leftsubtree(t leaves(rightsubtree(t))
))
n(leftsubtree(t)) 1 n(rightsubtree(t)) 1
2.0 2.0
่
เรารู้วา
n(t) n(leftsubtree(t)) n(rightsubtree(t)) 1
เพราะฉะนั้นเราสามารถแทนค่า n(t) ลงไปในอสมการได้ ผลคือได้
n(t ) 1
leaves(t )
2.0
External Path length
่
• ให้ t เป็ นต้นไม้ทวิภาคที่มีราก จะได้วา External Path
length, E(t) คือผลบวกของความลึกของทุกใบ
่
• ถ้า t เป็ นต้นไม้ทวิภาคที่มีจานวนใบเป็ น k (ซึ่ งมากกว่า 0) จะได้วา
E (t ) (k / 2) log 2 k
้
ต้นไม้คนหาแบบทวิภาค (Binary Search
Tree)
เป็ น empty tree หรื อเป็ นต้นไม้ซ่ ึง
• ทุกสมาชิกใน leftsubtree(t) มีค่าน้อยกว่าสมาชิกที่รากของ t
• ทุกสมาชิกใน rightsubtree(t) มีค่ามากกว่าสมาชิกที่รากของ t
• ทั้ง leftsubtree(t) และ rightsubtree(t) ต่างก็เป็ น
binary search tree
7
5 11
2 6 14
4
่
สื บค้นได้ง่าย เช่นถ้าเราต้องการหาว่า 4 อยูในต้นไม้หรื อไม่ เมื่อเราดูโนดแต่ละโนด
ั ่ ้
เราสามารถรู ้ได้ทนทีวาจะไปสารวจต้นไม้ขางใดต่อไป
่ ั
ทาให้เวลาในการค้นหาขึ้นอยูกบความสู งของต้นไม้เท่านั้น
ซึ่ งก็แปรตาม log ของจานวน โนด อีกทีหนึ่ง
1. class BinaryNode
2. {
3. // Constructors
4. BinaryNode( Comparable theElement )
5. {
6. this( theElement, null, null );
7. }
8. BinaryNode( Comparable theElement, BinaryNode lt, BinaryNode rt )
9. {
10. element = theElement;
11. left = lt;
12. right = rt;
13. }
14. // Friendly data; accessible by other package routines
15. Comparable element; // The data in the node
16. BinaryNode left; // Left child
17. BinaryNode right; // Right child
18. }
// BinarySearchTree class
//
// CONSTRUCTION: with no initializer
//
// ******************PUBLIC OPERATIONS*********************
// void insert( x ) --> Insert x
// void remove( x ) --> Remove x
// Comparable find( x ) --> Return item that matches x
// Comparable findMin( ) --> Return smallest item
// Comparable findMax( ) --> Return largest item
// boolean isEmpty( ) --> Return true if empty; else false
// void makeEmpty( ) --> Remove all items
// void printTree( ) --> Print tree in sorted order
private BinaryNode root;
1. public class BinarySearchTree
2. {
3. private BinaryNode root;
4. /**
5. * Construct the tree.
6. */
7. public BinarySearchTree( )
8. {
9. root = null;
10. }
11. /**
12. * Insert into the tree; duplicates are ignored.
13. * @param x the item to insert.
14. */
15. public void insert( Comparable x )
16. {
17. root = insert( x, root );
18. }
19. /**
20. * Remove from the tree. Nothing is done if x is not found.
21. * @param x the item to remove.
22. */
23. public void remove( Comparable x )
24. {
25. root = remove( x, root );
26. }
27. /**
28. * Find the smallest item in the tree.
29. * @return smallest item or null if empty.
30. */
31. public Comparable findMin( )
32. {
33. return elementAt( findMin( root ) );
34. }
35. /**
36. * Find the largest item in the tree.
37. * @return the largest item of null if empty.
38. */
39. public Comparable findMax( )
40. {
41. return elementAt( findMax( root ) );
42. }
43. /**
44. * Find an item in the tree.
45. * @param x the item to search for.
46. * @return the matching item or null if not found.
47. */
48. public Comparable find( Comparable x )
49. {
50. return elementAt( find( x, root ) );
51. }
52. /**
53. * Make the tree logically empty.
54. */
55. public void makeEmpty( )
56. {
57. root = null;
58. }
59. /**
60. * Test if the tree is logically empty.
61. * @return true if empty, false otherwise.
62. */
63. public boolean isEmpty( )
64. {
65. return root == null;
66. }
67. /**
68. * Print the tree contents in sorted order.
69. */
70. public void printTree( )
71. {
72. if( isEmpty( ) )
73. System.out.println( "Empty tree" );
74. else
75. printTree( root );
76. }
77. /**
78. * Internal method to get element field.
79. * @param t the node.
80. * @return the element field or null if t is null.
81. */
82. private Comparable elementAt( BinaryNode t )
83. {
84. return t == null ? null : t.element;
85. }
86. /**
87. * Internal method to insert into a subtree.
88. * @param x the item to insert.
89. * @param t the node that roots the tree.
90. * @return the new root.
91. */
92. private BinaryNode insert( Comparable x, BinaryNode t )
93. {
94. /* 1*/ if( t == null )
95. /* 2*/ t = new BinaryNode( x, null, null );
96. /* 3*/ else if( x.compareTo( t.element ) < 0 )
97. /* 4*/ t.left = insert( x, t.left );
98. /* 5*/ else if( x.compareTo( t.element ) > 0 )
99. /* 6*/ t.right = insert( x, t.right );
100./* 7*/ else
101./* 8*/ ; // Duplicate; do nothing
102./* 9*/ return t;
103. }
104. /**
105. * Internal method to remove from a subtree.
106. * @param x the item to remove.
107. * @param t the node that roots the tree.
108. * @return the new root.
109. */
110. private BinaryNode remove( Comparable x, BinaryNode t )
111. {
112. if( t == null )
113. return t; // Item not found; do nothing
114. if( x.compareTo( t.element ) < 0 )
115. t.left = remove( x, t.left );
116. else if( x.compareTo( t.element ) > 0 )
117. t.right = remove( x, t.right );
118. else if( t.left != null && t.right != null ) // Two children
119. {
120. t.element = findMin( t.right ).element;
121. t.right = remove( t.element, t.right );
122. }
123. else
124. t = ( t.left != null ) ? t.left : t.right;
125. return t;
126. }
X y
y y
การเอาสมาชิกค่าน้อยที่สุดของกิ่งขวาขึ้นมาแทนสมาชิกตัวที่
ถูกลบ
x y
y
การเอา subtree ขึ้นมาแทนที่โนดที่ถูกลบ
127. /**
128. * Internal method to find the smallest item in a subtree.
129. * @param t the node that roots the tree.
130. * @return node containing the smallest item.
131. */
132. private BinaryNode findMin( BinaryNode t )
133. {
134. if( t == null )
135. return null;
136. else if( t.left == null )
137. return t;
138. return findMin( t.left );
139. }
140. /**
141. * Internal method to find the largest item in a subtree.
142. * @param t the node that roots the tree.
143. * @return node containing the largest item.
144. */
145. private BinaryNode findMax( BinaryNode t )
146. {
147. if( t != null )
148. while( t.right != null )
149. t = t.right;
150. return t;
151. }
152. /**
153. * Internal method to find an item in a subtree.
154. * @param x is item to search for.
155. * @param t the node that roots the tree.
156. * @return node containing the matched item.
157. */
158. private BinaryNode find( Comparable x, BinaryNode t )
159. {
160. if( t == null )
161. return null;
162. if( x.compareTo( t.element ) < 0 )
163. return find( x, t.left );
164. else if( x.compareTo( t.element ) > 0 )
165. return find( x, t.right );
166. else
167. return t; // Match
168. }
169. /**
170. * Internal method to print a subtree in sorted order.
171. * @param t the node that roots the tree.
172. */
173. private void printTree( BinaryNode t )
174. {
175. if( t != null )
176. {
177. printTree( t.left );
178. System.out.println( t.element );
179. printTree( t.right );
180. }
181. }
182. // Test program
183. public static void main( String [ ] args )
184. {
185. BinarySearchTree t = new BinarySearchTree( );
186. final int NUMS = 4000;
187. final int GAP = 37;
188. System.out.println( "Checking... (no more output means
success)" );
189. for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS )
190. t.insert( new MyInteger( i ) );
191. for( int i = 1; i < NUMS; i+= 2 )
192. t.remove( new MyInteger( i ) );
193.if( NUMS < 40 )
194. t.printTree( );
195. if( ((MyInteger)(t.findMin( ))).intValue( ) != 2 ||
196. ((MyInteger)(t.findMax( ))).intValue( ) != NUMS - 2 )
197. System.out.println( "FindMin or FindMax error!" );
198. for( int i = 2; i < NUMS; i+=2 )
199. if( ((MyInteger)(t.find( new MyInteger( i ) ))).intValue( ) != i )
200. System.out.println( "Find error1!" );
201. for( int i = 1; i < NUMS; i+=2 )
202. {
203. if( t.find( new MyInteger( i ) ) != null )
204. System.out.println( "Find error2!" );
205. }
206. }
207. }
Related docs
Other docs by 4yeOQi7
Get documents about "