330 likes | 447 Views
AVL Tree. เป็น binary search tree ที่มี. สำหรับแต่ละโนด ความสูงของ left กับ right subtree ต่างกันได้อย่างมากแค่ 1 ถ้า tree เป็น empty tree เราให้ height เป็น -1 ความสูงของ AVL tree จะเป็น log N ค่าจริงคือ 1.44log(N+2)-.328
E N D
เป็น binary search tree ที่มี • สำหรับแต่ละโนด • ความสูงของ left กับ right subtree ต่างกันได้อย่างมากแค่ 1 • ถ้า tree เป็น empty tree เราให้ height เป็น -1 • ความสูงของ AVL tree จะเป็น log N • ค่าจริงคือ 1.44log(N+2)-.328 • เพราะว่าความสูงของ left กับ right subtree ต่างกันได้อย่างมากแค่ 1 • จำนวนโนดที่น้อยที่สุดของต้นไม้ที่มีความสูง h, s(h) = s(h-1)+s(h-2)+1 • เมื่อ h=0, s(h) =1 • เมื่อ h=1, s(h) =2 • คล้าย fibonacci
1 1 1 1 AVL Non-AVL
0 1 1 ใส่โนดใหม่เข้ามาทำให้เสียความเป็น AVL ฟังก์ชั่นต่างๆ • O(log(N)) หมด ยกเว้นการ insert กับ remove ซึ่งอาจทำให้เสียความเป็น AVL ไป
แก้ด้วย single rotation แก้ด้วย double rotation แก้ความไม่เป็น AVL ด้วยการ rotate • จากการ insert • โนดที่อยู่บนทางจากจุดที่ใส่ถึง root เท่านั้นที่มีความสูงเปลี่ยน • ถ้าเราไล่ดูจากจุดที่ insert ขึ้นไป ก็จะพบโนดที่เสียความเป็น AVL ที่อยู่ลึกสุด เราจะแก้ที่โนดนี้ โนดนี้มีได้สี่แบบเท่านั้น
ดึงขึ้น a b ย้ายที่เกาะ ไปเกาะโนดเจ้าปัญหา a b Z X X Y Y Z แก้ได้แล้วก็ไม่ต้อง rotate ที่ไหนต่ออีก Single rotation หลังจากการ insert
5 เสีย AVL จากโนดนี้ 5 2 8 2 7 0 1 1 4 7 1 4 6 8 1 3 6 3 ตัวอย่าง 1
3 3 3 rotate 2 2 2 1 1 3 ตัวอย่าง 2 • เริ่มจากไม่มีอะไร เรา insert 3,2,1 เสียความเป็น AVL To be continued
2 เสียความเป็น AVL 2 1 3 1 3 4 2 4 5 1 4 3 5 To be continued • ต่อไปเรา insert 4,5
เสียความเป็น AVL rotate 4 2 5 2 1 3 1 6 4 6 3 5 • ต่อไปเรา insert 6 To be continued
เสียความเป็น AVL 4 4 2 rotate 5 2 6 1 3 1 3 6 5 7 7 • ต่อไปเรา insert 7
a b b a Z X Y X Y Z Double rotation • Single rotation ไม่ได้แล้ว Y ไม่เปลี่ยนระดับ
โนดที่เจ๊ง a a b b Z Z X Y c X มีการ insert ดังนั้นต้องมีของแน่ๆ Y1 Y2
a a c b Z Z c b X Y2 X Y1 Y2 Y1 หมุนครั้งแรก
a c c b a Z b X Y2 Y1 Y2 Z X Y1 หมุนครั้งที่สอง
ให้ c ปล่อย Y1,Y2 แล้วกระโดดขึ้นหิ้ว a กับ b แทน c a a b b Z c X X Z Y1 Y2 Y1 Y2 ส่วน Y1, Y2 ก็หาที่เกาะข้างๆ • ไม่รู้ว่าข้าง Y1 หรือ Y2 กันแน่ที่ทำให้เสีย แต่ก็ไม่เป็นไรเพราะในตอนจบก็ลดระดับกันหมด
4 4 2 6 เจ๊ง 2 6 rotate 1 3 5 7 1 3 5 15 16 7 16 15 ตัวอย่าง • Insert 16,15 เสียความเป็น AVL ตอน insert 15
เจ๊ง 4 4 2 rotate 6 2 7 1 3 5 1 15 3 6 15 7 16 5 14 16 ต้องเป็นตัวกระโดด 14 • Insert 14
เจ๊ง ขวาสองทีแบบนี้ใช้ single rotation 4 7 2 7 4 15 1 3 rotate 6 15 2 6 14 16 5 14 16 1 3 5 13 13 • Insert 13
7 4 15 2 6 14 16 1 3 5 13 7 4 • Insert 12 ก็ทำให้ต้อง single rotate อีก 15 เจ๊ง rotate 2 6 13 16 1 3 5 12 14 12
7 เจ๊ง 7 4 4 • Insert 11 ก็ทำให้ต้อง single rotate อีก 13 15 rotate 15 12 2 6 6 13 2 16 1 3 1 14 16 5 3 5 12 14 11 11
7 4 13 เจ๊ง rotate 15 12 6 2 1 14 16 5 3 11 10 7 4 • Insert 10 ก็ทำให้ต้อง single rotate อีก 13 15 6 11 2 14 16 5 3 1 10 12
7 4 13 • Insert 8 ไม่มีอะไรเกิดขึ้น • Insert 9 ต่อเลย ง่ายๆ 6 15 2 11 เจ๊ง 5 3 1 10 12 14 16 8 9 10 8 9
class AvlNode • { • // Constructors • AvlNode( Comparable theElement ) • { • this( theElement, null, null ); • } • AvlNode( Comparable theElement, AvlNode lt, AvlNode rt ) • { • element = theElement; • left = lt; • right = rt; • height = 0; • } • // Friendly data; accessible by other package routines • Comparable element; // The data in the node • AvlNode left; // Left child • AvlNode right; // Right child • int height; // Height • } เดี๋ยวต้องมีเมธอดที่รีเทิร์น height เพื่อเราจะได้ไม่ต้องวุ่นวายถ้าโนดที่ต้องการดูเป็น null
ในหนังสือไม่มีการ remove • public class AvlTree • { private AvlNode root; • /** • * Construct the tree. • */ • public AvlTree( ) • { • root = null; • } • /** • * Insert into the tree; duplicates are ignored. • * @param x the item to insert. • */ • public void insert( Comparable x ) • { • root = insert( x, root ); • }
เมธอดเหมือน binary search Tree เยอะ ข้ามละกัน • /** • * Find the smallest item in the tree. • * @return smallest item or null if empty. • */ • public Comparable findMin( ) • { • return elementAt( findMin( root ) ); • } • /** • * Find the largest item in the tree. • * @return the largest item of null if empty. • */ • public Comparable findMax( ) • { • return elementAt( findMax( root ) ); • }
/** • * Return the height of node t, or -1, if null. • */ • private static int height( AvlNode t ) • { • return t == null ? -1 : t.height; • } • /** • * Return maximum of lhs and rhs. • */ • private static int max( int lhs, int rhs ) • { • return lhs > rhs ? lhs : rhs; • } ฟังก์ชั่นช่วย
t Insert • /** • * Internal method to insert into a subtree. • * @param x the item to insert. • * @param t the node that roots the tree. • * @return the new root. • */ • private AvlNode insert( Comparable x, AvlNode t ) • { • if( t == null ) • t = new AvlNode( x, null, null ); • else if( x.compareTo( t.element ) < 0 ) • { • t.left = insert( x, t.left ); • if( height( t.left ) - height( t.right ) == 2 ) • if( x.compareTo( t.left.element ) < 0 ) • t = rotateWithLeftChild( t ); • else • t = doubleWithLeftChild( t ); • } ถ้า==2เป็นจริง x ต้องอยู่ต่ำกว่านี้
t • else if( x.compareTo( t.element ) > 0 ) • { • t.right = insert( x, t.right ); • if( height( t.right ) - height( t.left ) == 2 ) • if( x.compareTo( t.right.element ) > 0 ) • t = rotateWithRightChild( t ); • else • t = doubleWithRightChild( t ); • } • else • ; // Duplicate; do nothing • t.height = max( height( t.left ), height( t.right ) ) + 1; • return t; • }
k2 k1 k1 k2 • /** • * Rotate binary tree node with left child. • * For AVL trees, this is a single rotation for case 1. • * Update heights, then return new root. • */ • private static AvlNode rotateWithLeftChild( AvlNode k2 ) • { • AvlNode k1 = k2.left; • k2.left = k1.right; • k1.right = k2; • k2.height = max( height( k2.left ), height( k2.right ) ) + 1; • k1.height = max( height( k1.left ), k2.height ) + 1; • return k1; • }
k1 k2 k2 k1 • /** • * Rotate binary tree node with right child. • * For AVL trees, this is a single rotation for case 4. • * Update heights, then return new root. • */ • private static AvlNode rotateWithRightChild( AvlNode k1 ) • { • AvlNode k2 = k1.right; • k1.right = k2.left; • k2.left = k1; • k1.height = max( height( k1.left ), height( k1.right ) ) + 1; • k2.height = max( height( k2.right ), k1.height ) + 1; • return k2; • }
k3 k3 k1 k2 Z k2 Z k2 k1 k3 X k1 Y2 X Z Y1 Y2 X Y1 Y2 Y1 • /** • * Double rotate binary tree node: first left child • * with its right child; then node k3 with new left child. • * For AVL trees, this is a double rotation for case 2. • * Update heights, then return new root. • */ • private static AvlNode doubleWithLeftChild( AvlNode k3 ) • { • k3.left = rotateWithRightChild( k3.left ); • return rotateWithLeftChild( k3 ); • }
k1 k1 k2 k3 Z k2 Z k1 k3 k2 X k3 Y2 X Y1 Z Y2 Y2 Y1 X Y1 • /** • * Double rotate binary tree node: first right child • * with its left child; then node k1 with new right child. • * For AVL trees, this is a double rotation for case 3. • * Update heights, then return new root. • */ • private static AvlNode doubleWithRightChild( AvlNode k1 ) • { • k1.right = rotateWithLeftChild( k1.right ); • return rotateWithRightChild( k1 ); • }