AVL Tree

AVL Tree
เป็ น 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
ฟังก์ชนั่ ต่ำงๆ
• O(log(N)) หมด ยกเว้นกำร insert กับ remove ซึ่งอำจ
ทำให้เสี ยควำมเป็ น AVL ไป
1
1
0
ใส่ โนดใหม่เข้ำมำทำให้เสี ยควำมเป็ น AVL
แก้ควำมไม่เป็ น AVL ด้วยกำร rotate
• จำกกำร insert
– โนดที่อยูบ่ นทำงจำกจุดที่ใส่ ถึง root เท่ำนั้นที่มีควำมสู งเปลี่ยน
– ถ้ำเรำไล่ดูจำกจุดที่ insert ขึ้นไป ก็จะพบโนดที่เสี ยควำมเป็ น AVL ที่
อยูล่ ึกสุ ด เรำจะแก้ที่โนดนี้ โนดนี้มีได้สี่แบบเท่ำนั้น
แก้ดว้ ย single rotation
แก้ดว้ ย double rotation
Single rotation หลังจำกกำร insert
ดึงขึ้น
a
b
ย้ำยที่เกำะ ไปเกำะโนดเจ้ำปัญหำ
b
a
Z
Y
X
X
แก้ได้แล้วก็ไม่ตอ้ ง rotate ที่ไหนต่ออีก
Y
Z
ตัวอย่ำง 1
เสี ย AVL จำกโนดนี้
5
2
1
8
1
7
4
1
3
6
5
2
0
1
7
4
3
6
8
ตัวอย่ำง 2
• เริ่ มจำกไม่มีอะไร เรำ insert 3,2,1
3
เสี ยควำมเป็ น AVL
3
3
2
rotate
2
1
2
1
To be continued
3
2
• ต่อไปเรำ insert 4,5
2
1
เสี ยควำมเป็ น AVL
1
3
3
4
4
2
5
1
4
3
5
To be continued
• ต่อไปเรำ insert 6
เสี ยควำมเป็ น AVL
2
rotate
1
4
4
2
3
5
5
1
3
6
6
To be continued
• ต่อไปเรำ insert 7
เสี ยควำมเป็ น AVL
4
2
1
rotate
5
3
2
1
6
7
4
6
3
5
7
Double rotation
• Single rotation ไม่ได้แล้ว
a
b
b
a
Z
X
X
Y
Y
Y ไม่เปลี่ยนระดับ
Z
โนดที่เจ๊ง
a
a
b
b
Z
Z
c
X
Y
X
มีกำร insert ดังนั้น
ต้องมีของแน่ๆ
Y1 Y2
หมุนครั้งแรก
a
a
c
b
c
Z
Z
b
Y2
X
Y1 Y2
X
Y1
หมุนครั้งที่สอง
a
c
c
b
Z
b
Y2
X
a
Y1
X
Y1
Y2
Z
ให้ c ปล่อย Y1,Y2 แล้วกระโดดขึ้นหิ้ ว a กับ b แทน
c
a
b
b
c
Z
X
X
Y1 Y2
a
Z
Y1 Y2
ส่ วน Y1, Y2 ก็หำที่เกำะข้ำงๆ
• ไม่รู้วำ่ ข้ำง Y1 หรื อ Y2 กันแน่ที่ทำให้เสี ย แต่กไ็ ม่เป็ นไรเพรำะในตอนจบ
ก็ลดระดับกันหมด
ตัวอย่ำง
• Insert 16,15 เสี ยควำมเป็ น AVL ตอน insert 15
4
4
2
1
6
3
5
เจ๊ง
7
2
rotate
1
6
3
5
15
16
7
15
16
• Insert 14
เจ๊ง
4
4
2
1
rotate
6
3
5
1
15
7
16
ต้องเป็ นตัวกระโดด
14
2
7
3
6
5
15
14
16
เจ๊ง
• Insert 13
ขวำสองทีแบบนี้ใช้ single rotation
4
7
2
1
7
3
6
4
15
rotate
2
5
13
14 16
15
1
6 14 16
3 5 13
• Insert 12 ก็ทำให้ตอ้ ง single rotate อีก
7
4
2
1
7
4
เจ๊ง 15
6 14 16
3 5 13
12
rotate
2
1
15
6 13 16
3 5 12 14
• Insert 11 ก็ทำให้ตอ้ ง single rotate อีก
เจ๊ง
7
4
2
1
7
4
15
13
rotate
6 13 16
3 5 12 14
11
2
1
6
3 5 11
15
12
14
16
• Insert 10 ก็ทำให้ตอ้ ง single rotate อีก
7
4
2
1
เจ๊ง
7
15
6 12
3 5 11
10
4
13
14
13
rotate
16
2
1
6 11
3 5 10 12 14
15
16
• Insert 8 ไม่มีอะไรเกิดขึ้น
• Insert 9 ต่อเลย ง่ำยๆ
7
4
6
2
1
13
3
5
11
เจ๊ง
10 12 14
15
16
8
9
9
8
10
1.
2.
3.
4.
5.
6.
7.
class AvlNode
{
// Constructors
AvlNode( Comparable theElement )
{
this( theElement, null, null );
}
8.
9.
10.
11.
12.
13.
14.
AvlNode( Comparable theElement, AvlNode lt, AvlNode rt )
{
element = theElement;
left = lt;
right = rt;
height = 0;
}
15.
16.
17.
18.
19.
20.
// 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
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
public class AvlTree
{ private AvlNode root;
/**
* Construct the tree.
*/
public AvlTree( )
{
root = null;
}
ในหนังสื อไม่มีกำร remove
/**
* Insert into the tree; duplicates are ignored.
* @param x the item to insert.
*/
public void insert( Comparable x )
{
root = insert( x, root );
}
18.
/**
19.
20.
21.
22.
23.
24.
25.
* Find the smallest item in the tree.
* @return smallest item or null if empty.
*/
public Comparable findMin( )
{
return elementAt( findMin( root ) );
}
26.
27.
28.
29.
30.
31.
32.
33.
/**
* Find the largest item in the tree.
* @return the largest item of null if empty.
*/
public Comparable findMax( )
{
return elementAt( findMax( root ) );
}
เมธอดเหมือน
binary search
Tree เยอะ ข้ำมละกัน
1.
/**
2.
3.
4.
5.
6.
7.
* Return the height of node t, or -1, if null.
*/
private static int height( AvlNode t )
{
return t == null ? -1 : t.height;
}
8.
9.
10.
11.
12.
13.
14.
/**
* Return maximum of lhs and rhs.
*/
private static int max( int lhs, int rhs )
{
return lhs > rhs ? lhs : rhs;
}
ฟังก์ชนั่ ช่วย
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
/**
* Internal method to insert into a subtree.
* @param x the item to insert.
* @param t the node that roots the tree.
Insert
* @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 )
{
ถ้ำ==2เป็ นจริ ง x ต้องอยูต่ ่ำกว่ำนี้
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 );
}
t
t
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
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;
}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
/**
k2
* Rotate binary tree node with left child.
k1
* 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
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
/**
* 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;
}
k1
k2
k2
k1
/**
* 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 );
}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
k3
k1
k2
X
Y1 Y2
k3
Z
k2
k2
k1
Z
Y2
X Y1
k1
k3
X Y1 Y2 Z
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
/**
* 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 );
}
k1
Z
k1
k3
k2
Z
X
Y2 Y1
k2
k2
Y2
k1
k3
k3
Y1 X
Z Y2 Y1 X