Soongle's Morgorithm
AVL 트리 본문
AVL 트리란, George Adelson-Velsky와 Evgenii Landis가 발표한 최초의 균형잡힌 이진트리(balanced binary tree)이다.
AVL 트리 클래스를 Node구조체를 사용한 링크 표현법으로 구현하였다.
AVL 트리의 가장 핵심적인 기술은 바로 회전(Rotation)이다.
RR, LL, RL, LR 네 가지 경우에서의 회전을 통해 트리 전체의 좌우 균형을 맞추기 때문이다.
이렇게 균형이 맞춰진 트리는 값을 탐색할 때 최악의 경우에도 O(log n)의 시간안에 탐색을 끝낼 수 있다.
각각의 회전을 해야하는 경우는 아래와 같다
-
RR : 오른쪽, 오른쪽으로 치우친 경우 → 현재 노드 기준으로 왼쪽으로 회전시킨다
-
LL : 왼쪽, 왼쪽으로 치우친 경우 → 현재 노드 기준으로 오른쪽으로 회전시킨다
-
RL : 오른쪽, 왼쪽으로 치우친 경우 → 자식노드 기준으로 오른쪽 회전시킨 후, 현재 노드 기준으로 왼쪽 회전시킨다
-
LR : 왼쪽, 오른쪽으로 치우친 경우 → 자식노드 기준으로 왼쪽 회전시킨 후, 현재 노드 기준으로 오른쪽 회전시킨다
네 가지 회전 소스코드
Node* RR(Node* parent)
{
Node* child = parent->right;
parent->right = child->left;
child->left = parent;
return child;
}
Node* LL(Node* parent)
{
Node* child = parent->left;
parent->left = child->right;
child->right = parent;
return child;
}
Node* LR(Node* parent)
{
Node* child = parent->left;
parent->left = RR(child);
return LL(parent);
}
Node* RL(Node* parent)
{
Node* child = parent->right;
parent->right = LL(child);
return RR(parent);
}
회전을 통해 균형을 맞추는 balance 함수
factor 변수는 tmp의 균형인수이다 (왼쪽자식의 높이 - 오른쪽자식의 높이)
void balance(Node* &tmp)
{
if(tmp != NULL)
{
int factor = diff(tmp);
if(factor > 1)
{
if(diff(tmp->left) > 0)
{
tmp = LL(tmp);
cout<<"LL rotation"<<endl;
}
else
{
tmp = LR(tmp);
cout<<"LR rotation"<<endl;
}
}
else if(factor < -1)
{
if(diff(tmp->right) > 0)
{
tmp = RL(tmp);
cout<<"RL rotation"<<endl;
}
else
{
tmp = RR(tmp);
cout<<"RR rotation"<<endl;
}
}
}
}
삽입과 삭제 연산을 한 뒤 항상 균형을 맞추어 주어야 한다
더보기
bool recur_insert(Node* &tree, int item)
{
bool flag;
if(tree == NULL)
{
tree = new Node;
tree->data = item;
tree->left = NULL;
tree->right = NULL;
return true;
}
if(item == tree->data) return false;
else if(item < tree->data)
{
flag = recur_insert(tree->left, item);
balance(tree);
return flag;
}
else
{
flag = recur_insert(tree->right, item);
balance(tree);
return flag;
}
}
bool recur_remove(Node* &tree, int item)
{
if(tree == NULL) return false;
if(tree->data == item)
{
Node* tmp;
if(tree->left == NULL)
{
tmp = tree;
tree = tree->right;
delete tmp;
balance(tree);
return true;
}
else if(tree->right == NULL)
{
tmp = tree;
tree = tree->left;
delete tmp;
balance(tree);
return true;
}
else
{
tmp = tree->right;
while(tmp != NULL)
{
tmp = tmp->left;
}
tree->data = tmp->data;
recur_remove(tree->right, tmp->data);
balance(tree);
return true;
}
}
else if(tree->data > item) return recur_remove(tree->left, item);
else return recur_remove(tree->right, item);
}
소스코드
더보기
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
struct Node
{
int data;
Node* left;
Node* right;
};
class AVL_Tree
{
public:
AVL_Tree();
int height();
bool insert(int item);
bool remove(int item);
void display();
void inorder();
void preorder();
void postorder();
private:
Node* root;
};
AVL_Tree::AVL_Tree()
{
root = NULL;
}
int recur_height(Node* tree)
{
if(tree == NULL) return 0;
return max(recur_height(tree->left), recur_height(tree->right)) + 1;
}
int AVL_Tree::height()
{
return recur_height(root);
}
int diff(Node* tree)
{
return recur_height(tree->left) - recur_height(tree->right);
}
Node* RR(Node* parent)
{
Node* child = parent->right;
parent->right = child->left;
child->left = parent;
return child;
}
Node* LL(Node* parent)
{
Node* child = parent->left;
parent->left = child->right;
child->right = parent;
return child;
}
Node* LR(Node* parent)
{
Node* child = parent->left;
parent->left = RR(child);
return LL(parent);
}
Node* RL(Node* parent)
{
Node* child = parent->right;
parent->right = LL(child);
return RR(parent);
}
void balance(Node* &tmp)
{
if(tmp != NULL)
{
int factor = diff(tmp);
if(factor > 1)
{
if(diff(tmp->left) > 0)
{
tmp = LL(tmp);
cout<<"LL rotation"<<endl;
}
else
{
tmp = LR(tmp);
cout<<"LR rotation"<<endl;
}
}
else if(factor < -1)
{
if(diff(tmp->right) > 0)
{
tmp = RL(tmp);
cout<<"RL rotation"<<endl;
}
else
{
tmp = RR(tmp);
cout<<"RR rotation"<<endl;
}
}
}
}
bool recur_insert(Node* &tree, int item)
{
bool flag;
if(tree == NULL)
{
tree = new Node;
tree->data = item;
tree->left = NULL;
tree->right = NULL;
return true;
}
if(item == tree->data) return false;
else if(item < tree->data)
{
flag = recur_insert(tree->left, item);
balance(tree);
return flag;
}
else
{
flag = recur_insert(tree->right, item);
balance(tree);
return flag;
}
}
bool AVL_Tree::insert(int item)
{
return recur_insert(root, item);
}
bool recur_remove(Node* &tree, int item)
{
if(tree == NULL) return false;
if(tree->data == item)
{
Node* tmp;
if(tree->left == NULL)
{
tmp = tree;
tree = tree->right;
delete tmp;
balance(tree);
return true;
}
else if(tree->right == NULL)
{
tmp = tree;
tree = tree->left;
delete tmp;
balance(tree);
return true;
}
else
{
tmp = tree->right;
while(tmp != NULL)
{
tmp = tmp->left;
}
tree->data = tmp->data;
recur_remove(tree->right, tmp->data);
balance(tree);
return true;
}
}
else if(tree->data > item) return recur_remove(tree->left, item);
else return recur_remove(tree->right, item);
}
bool AVL_Tree::remove(int item)
{
return recur_remove(root, item);
}
void recur_display(Node* tree)
{
if(tree != NULL)
{
recur_display(tree->left);
cout<<"<"<<tree->data<<"> ";
recur_display(tree->right);
}
}
void AVL_Tree::display()
{
if(root == NULL) cout<<"Tree is Empty"<<endl;
else
{
recur_display(root);
cout<<endl;
}
}
void recur_inorder(Node* tree)
{
if(tree != NULL)
{
recur_inorder(tree->left);
cout<<tree->data<<" ";
recur_inorder(tree->right);
}
}
void AVL_Tree::inorder()
{
if(root == NULL) cout<<"Tree is Empty"<<endl;
else
{
cout<<" => : ";
recur_inorder(root);
cout<<endl;
}
}
void recur_preorder(Node* tree)
{
if(tree != NULL)
{
cout<<tree->data<<" ";
recur_preorder(tree->left);
recur_preorder(tree->right);
}
}
void AVL_Tree::preorder()
{
if(root == NULL) cout<<"Tree is Empty"<<endl;
else
{
cout<<" => : ";
recur_preorder(root);
cout<<endl;
}
}
void recur_postorder(Node* tree)
{
if(tree != NULL)
{
recur_postorder(tree->left);
recur_postorder(tree->right);
cout<<tree->data<<" ";
}
}
void AVL_Tree::postorder()
{
if(root == NULL) cout<<"Tree is Empty"<<endl;
else
{
cout<<" => : ";
recur_postorder(root);
cout<<endl;
}
}
int main()
{
AVL_Tree avl;
string command;
int item;
while(1)
{
cin>>command;
if(command == "insert")
{
cin >> item;
avl.insert(item);
}
if(command == "remove")
{
cin >> item;
avl.remove(item);
}
else if(command == "display")
{
avl.display();
}
else if(command == "inorder")
{
avl.inorder();
}
else if(command == "preorder")
{
avl.preorder();
}
else if(command == "postorder")
{
avl.postorder();
}
else if(command == "exit")
{
break;
}
}
return 0;
}
전체 소스코드
'Data Structure > Tree' 카테고리의 다른 글
이진 탐색 트리(Binary Search Tree) (1) | 2019.06.13 |
---|
Comments