AVL Tree
AVL Tree
AVL Tree secara dasarnya sama seperti Binary Search Tree yang umumnya,
namun tree ini memiliki perbedaan-perbedaan yang mendasar:
- Bisa dibilang bahwa tree ini hampir selalu berupa perfect binary tree. Hal ini terjadi karena AVL Tree mengoptimasi cabang-cabang anakannya sehingga cabangnya tidak terlalu ke kiri atau ke kanan
- Akibatnya, perbedaan ketinggian pada setiap cabang yang terdapat di tree ini tidak boleh lebih dari 1. Inilah yang kita sebut sebagai Balanced Binary Tree.
Berikut ini adalah contoh perbandingan gambar AVL Tree dan yang bukan:
Kiri – Bukan AVL Tree karena perbedaan ketinggian di node 8 dan 18 lebih dari 1, namun gambar kanan memenuhi persyaratan AVL Tree
Mengapa AVL Tree perlu dipakai?
Bayangkan jika kita menggunakan binary search tree. Jika kita lihat,
anakan yang lebih besar dari parentnya, maka nodenya ditaruh di kanan dan
sebaliknya. Bagaimana jika data yang diinsert selalu lebih besar dari parentnya
atau sebaliknya? Otomatis, BST ini akan menjadi skewed binary tree, dimana
perbedaan ketinggian ini bahkan bisa setara dengan jumlah node di tree
tersebut. Alhasil, proses insertion, deletion, dan searching bisa sama seperti
linked list biasa. Oleh karena itu, itulah sebabnya AVL Tree diperlukan untuk
memecahkan kasus ini.
Untuk menyeimbangkan tree ini, maka diperlukan yang namanya left and
right rotation.
Syarat-syarat Balanced Binary Tree: jika pebedaan ketinggian antar
anakan node <= 1.
Untuk proses insertion, deletion, dan searching sama seperti binary
search tree pada umumnya. Namun, di akhir operasi tersebut, Ia mentraverse up
untuk mengecek apakah node tersebut menyalahi aturan Balanced Binary Tree.
Macam-macam bentuk rotation:
·
Single
Rotation (left-left atau right right):
Pada contoh diatas termasuk left rotation, karena
dari 30 ke 22 ke kiri, dan dari 22 ke 15 ke kiri juga.
·
Double
Rotation (left – right atau right - left):
Rotasi pertama: Left - right
Rotasi kedua: left-left
Contoh implementasi AVL Tree (insertion):
// C++ program to insert a node in
AVL tree
#include<bits/stdc++.h>
using namespace std;
// An AVL tree node
class Node
{
public:
int
key;
Node
*left;
Node
*right;
int
height;
};
// A utility function to get maximum
// of two integers
int max(int a, int b);
// A utility function to get
the
// height of the tree
int height(Node *N)
{
if (N ==
NULL)
return
0;
return
N->height;
}
// A utility function to get maximum
// of two integers
int max(int a, int b)
{
return (a
> b)? a : b;
}
/* Helper function that allocates
a
new node with the
given key and
NULL left and
right pointers. */
Node* newNode(int key)
{
Node* node =
new Node();
node->key
= key;
node->left
= NULL;
node->right
= NULL;
node->height
= 1; // new node is initially
//
added at leaf
return(node);
}
// A utility function to right
// rotate subtree rooted with
y
// See the diagram given
above.
Node *rightRotate(Node *y)
{
Node *x =
y->left;
Node *T2 =
x->right;
// Perform
rotation
x->right
= y;
y->left =
T2;
// Update
heights
y->height
= max(height(y->left),
height(y->right))
+ 1;
x->height
= max(height(x->left),
height(x->right))
+ 1;
// Return
new root
return
x;
}
// A utility function to left
// rotate subtree rooted with
x
// See the diagram given
above.
Node *leftRotate(Node *x)
{
Node *y =
x->right;
Node *T2 =
y->left;
// Perform
rotation
y->left =
x;
x->right
= T2;
// Update
heights
x->height
= max(height(x->left),
height(x->right))
+ 1;
y->height
= max(height(y->left),
height(y->right))
+ 1;
// Return
new root
return
y;
}
// Get Balance factor of node
N
int getBalance(Node *N)
{
if (N ==
NULL)
return
0;
return
height(N->left) - height(N->right);
}
// Recursive function to insert a
key
// in the subtree rooted with node
and
// returns the new root of the
subtree.
Node* insert(Node* node, int
key)
{
/* 1.
Perform the normal BST insertion */
if (node ==
NULL)
return(newNode(key));
if (key <
node->key)
node->left
= insert(node->left, key);
else if (key
> node->key)
node->right
= insert(node->right, key);
else //
Equal keys are not allowed in BST
return
node;
/* 2. Update
height of this ancestor node */
node->height
= 1 + max(height(node->left),
height(node->right));
/* 3. Get
the balance factor of this ancestor
node
to check whether this node became
unbalanced
*/
int balance
= getBalance(node);
// If this
node becomes unbalanced, then
// there are
4 cases
// Left Left
Case
if (balance
> 1 && key < node->left->key)
return
rightRotate(node);
// Right
Right Case
if (balance
< -1 && key > node->right->key)
return
leftRotate(node);
// Left
Right Case
if (balance
> 1 && key > node->left->key)
{
node->left
= leftRotate(node->left);
return
rightRotate(node);
}
// Right
Left Case
if (balance
< -1 && key < node->right->key)
{
node->right
= rightRotate(node->right);
return
leftRotate(node);
}
/* return
the (unchanged) node pointer */
return
node;
}
Node* deleteNode(Node* root, int
key)
{
// STEP 1:
PERFORM STANDARD BST DELETE
if (root ==
NULL)
return
root;
// If the
key to be deleted is smaller
// than the
root's key, then it lies
// in left
subtree
if ( key
< root->key )
root->left
= deleteNode(root->left, key);
// If the
key to be deleted is greater
// than the
root's key, then it lies
// in right
subtree
else if( key
> root->key )
root->right
= deleteNode(root->right, key);
// if key is
same as root's key, then
// This is
the node to be deleted
else
{
//
node with only one child or no child
if(
(root->left == NULL) ||
(root->right
== NULL) )
{
Node
*temp = root->left ?
root->left
:
root->right;
//
No child case
if
(temp == NULL)
{
temp
= root;
root
= NULL;
}
else
// One child case
*root
= *temp; // Copy the contents of
//
the non-empty child
free(temp);
}
else
{
//
node with two children: Get the inorder
//
successor (smallest in the right subtree)
Node*
temp = minValueNode(root->right);
//
Copy the inorder successor's
//
data to this node
root->key
= temp->key;
//
Delete the inorder successor
root->right
= deleteNode(root->right,
temp->key);
}
}
// If the
tree had only one node
// then
return
if (root ==
NULL)
return
root;
// STEP 2:
UPDATE HEIGHT OF THE CURRENT NODE
root->height
= 1 + max(height(root->left),
height(root->right));
// STEP 3:
GET THE BALANCE FACTOR OF
// THIS NODE
(to check whether this
// node
became unbalanced)
int balance
= getBalance(root);
// If this
node becomes unbalanced,
// then
there are 4 cases
// Left Left
Case
if (balance
> 1 &&
getBalance(root->left)
>= 0)
return
rightRotate(root);
// Left
Right Case
if (balance
> 1 &&
getBalance(root->left)
< 0)
{
root->left
= leftRotate(root->left);
return
rightRotate(root);
}
// Right
Right Case
if (balance
< -1 &&
getBalance(root->right)
<= 0)
return
leftRotate(root);
// Right
Left Case
if (balance
< -1 &&
getBalance(root->right)
> 0)
{
root->right
= rightRotate(root->right);
return
leftRotate(root);
}
return
root;
}
// A utility function to print
preorder
// traversal of the tree.
// The function also prints
height
// of every node
void preOrder(Node *root)
{
if(root !=
NULL)
{
cout
<< root->key << " ";
preOrder(root->left);
preOrder(root->right);
}
}
// Driver Code
int main()
{
Node *root =
NULL;
/*
Constructing tree given in
the above
figure */
root =
insert(root, 10);
root =
insert(root, 20);
root =
insert(root, 30);
root =
insert(root, 40);
root =
insert(root, 50);
root =
insert(root, 25);
root =
deleteNode(root, 20);
root = deleteNode(root, 50);
cout
<< "Preorder traversal of the "
"constructed
AVL tree is \n";
preOrder(root);
return
0;
}
Source code:
Untuk AVL Tree, Ia sebaiknya digunakan apabila proses insertion dan deletion
tidak terlalu banyak. Bisa jadi pada saat insertion atau deletion, Ia membutuhkan
lebih dari satu rotasi. Itulah sebabnya, AVL Tree lebih digunakan untuk proses
searching yang lebih sering. Jika Anda ingin melakukan proses insertion dan
deletion yang lebih sering, gunakanlah Red Black Tree.
Comments
Post a Comment