Skip to content

Instantly share code, notes, and snippets.

@gowoonsori
Created January 26, 2021 07:15
Show Gist options
  • Save gowoonsori/3ea3a2d0fb8b9f3f7c6ac4d8876d8a85 to your computer and use it in GitHub Desktop.
Save gowoonsori/3ea3a2d0fb8b9f3f7c6ac4d8876d8a85 to your computer and use it in GitHub Desktop.
C++ 이용한 AVL Tree
/*
* C++ 이용하여 AVL Tree 구현하기
*
* 목적 : AVL Tree 공부 하기 위해 작성했으며,
* C++ 이용하여 작성하시는 분들에게 도움이 되고자 했다.
*
* 설명 : key 값은 int만 가능 하며 중복 key는 허용 x
* 단순 연결 리스트로 구현
*
* class AVLTree
*
* 변수 : root => root node
*
* 생성자 : RBTREE => root 를 null로 초기화
*
* 함수 : IsKey => key값이 있는지 검사하는 함수
*
* Insert => 재귀를 이용한 삽입 함수 (최종적으로 root를 return)
* Delete => 재귀를 이용한 삭제 함수 (최종적을 root를 return)
* Balancing => 삽입 / 삭제후 BF 검사하여 규칙깨졌을시 재조정 함수
* Transplant => 삭제 시 이용하며, 삭제할 노드의 자식 노드를 부모노드에 연결해주는 함수
*
* getHeight(x) => x의 높이 getter
* getBalanceBacotr(x) => x의 BF 계산하여 return
* RotateRight(x) => x기준 오른쪽으로 회전
* RotateLeft(x) => x기준 왼쪽으로 회전
*
* Inorder,Preorder,Postorder => 순회 함수
* tree_minimum(x), tree_maximum(x) => 노드 x 기준으로 가장 왼쪽, 오른쪽 return 함수
*
* DisplayMenu, SelectMenu => 초기 Menu판 print 함수
* Insert_helper,Delete_helper,order_helper,print_helper => 각각 이벤트 수행시 입력받고 조건 에러 처리 위한 함수 와 tree print 해주는 함수
*
* Balancing에서 각 case에 대한 설명은 github에 적어 놓았다.
*
* 작성자 : gowoonsori
* github : https://github.com/gowoonsori/my-tech/tree/master/dataStructure/Tree
*/
#include <algorithm> // max() 함수 이용
#include <iostream>
struct node {
int key;
node *left = nullptr;
node *right = nullptr;
int height = 1;
};
typedef node *NodePtr;
class AVLTREE {
private:
NodePtr root; //루트 노드
//key값이 있는지 없는지 검사 있으면 pointer 값, 없으면 nullptr
NodePtr IsKey(int item) {
NodePtr t = root;
/*key값을 찾거나 없다면 break*/
while (t != nullptr && t->key != item) {
t = (item < t->key) ? t->left : t->right;
}
return t;
}
/*새로운 key 삽입함수로 root노드 반환*/
NodePtr Insert(NodePtr r, int item) {
/*새로운 노드 삽입*/
if (r == nullptr) {
NodePtr z = new node;
z->key = item;
r = z;
return r;
} else if (r->key < item) { //item이 key값보다 크다면 오른쪽으로 이동
r->right = Insert(r->right, item);
} else { //item이 key값보다 작다면 왼쪽으로 이동
r->left = Insert(r->left, item);
}
r->height = std::max(getHeight(r->left), getHeight(r->right)) + 1;
Balancing(r, item); //새로운 노드가 추가되었으므로 재귀적으로 부모노드들 높이 1증가 시켜주고
//Balace Factor 측정하여 2이상이라면 재조정함수
return r;
}
/*key 삭제 함수*/
NodePtr Delete(NodePtr r, int item) {
if (r->key > item && r->left != nullptr) {
r->left = Delete(r->left, item);
} else if (r->key < item && r->right != nullptr) {
r->right = Delete(r->right, item);
} else if (r->key == item) {
Transplant(r);
}
/*root를 지운게 아니라면*/
if (r != nullptr) {
r->height = std::max(getHeight(r->left), getHeight(r->right)) + 1;
Balancing(r, item);
}
return r;
}
/* balance Factor 측정후 재조정*/
void Balancing(NodePtr &r, int item) {
int bF = getBalanceFactor(r);
//case 1 (left left)
if (bF > 1 && item < r->left->key) {
r = RotateRight(r);
}
//case 2 (left right)
else if (bF > 1 && item > r->left->key) {
r->left = RotateLeft(r->left);
r = RotateRight(r);
}
//case 3 (right right)
else if (bF < -1 && item > r->right->key) {
r = RotateLeft(r);
}
//case 4 ( right left)
else if (bF < -1 && item < r->right->key) {
r->right = RotateRight(r->right);
r = RotateLeft(r);
}
}
/* 삭제시 자식 이식 함수*/
void Transplant(NodePtr &x) {
NodePtr y = x; //y를 통해 노드 삭제
if (x->left == nullptr) {
x = x->right;
} else if (x->right == nullptr) {
x = x->left;
} else {
NodePtr z = x->right; //z : 삭제할 x의 다음으로 가장 작은 수
NodePtr pZ = x; //p[z] : z의 부모 노드
/* 오른쪽 자식중 가장 작은 값*/
while (z->left != nullptr) {
pZ = z;
z = z->left;
}
x->key = z->key; //successor과 key값 교환
/*오른쪽 자식이 가장 작다면*/
if (pZ == x) {
x->right = z->right; // z의 오른쪽 자식 붙여주기
} else {
pZ->left = z->right; // 오른쪽 자식의 왼쪽 자식이 있다면
} // 그 z(successor)의 오른쪽 자식 p[z]의 왼쪽에 붙여주기
y = z; //값 삭제를 위해 y <- z;
}
delete y;
}
/*높이 getter */
int getHeight(NodePtr r) {
if (r == nullptr)
return 0;
else
return r->height;
}
/*좌우 자식 깊이 비교하여 Balnace Factor get*/
int getBalanceFactor(NodePtr r) {
return getHeight(r->left) - getHeight(r->right);
}
/*x를 중심으로 왼쪽으로 회전*/
NodePtr RotateLeft(NodePtr x) {
NodePtr y = x->right;
x->right = y->left;
y->left = x;
//위치가 바뀌었으므로 높이 재조정
x->height = std::max(getHeight(x->left), getHeight(x->right)) + 1;
y->height = std::max(getHeight(y->left), getHeight(y->right)) + 1;
return y;
}
/*y를 중심으로 오른쪽으로 회전*/
NodePtr RotateRight(NodePtr y) {
NodePtr x = y->left;
y->left = x->right;
x->right = y;
//위치가 바뀌었으므로 높이 재조정
y->height = std::max(getHeight(y->left), getHeight(y->right)) + 1;
x->height = std::max(getHeight(x->left), getHeight(x->right)) + 1;
return x;
}
/*show tree*/
void print_helper(NodePtr root, std::string indent, bool last) {
// print the tree structure on the screen
if (root != nullptr) {
std::cout << indent;
if (last) {
std::cout << "R----";
indent += " ";
} else {
std::cout << "L----";
indent += "| ";
}
int height = std::max(getHeight(root->left), getHeight(root->right)) + 1;
std::cout << root->key << " (" << height << ")" << std::endl;
print_helper(root->left, indent, false);
print_helper(root->right, indent, true);
}
}
/*중위순회*/
void Inorder(NodePtr target) {
if (target == nullptr)
return;
Inorder(target->left);
std::cout << target->key << " ";
Inorder(target->right);
}
/*후위순회*/
void Postorder(NodePtr target) {
if (target == nullptr)
return;
Postorder(target->left);
Postorder(target->right);
std::cout << target->key << " ";
}
/*전위순회*/
void Preorder(NodePtr target) {
if (target == nullptr)
return;
std::cout << target->key << " ";
Preorder(target->left);
Preorder(target->right);
}
public:
AVLTREE() {
this->root = nullptr;
}
//최솟값 찾기
NodePtr tree_minimum(NodePtr x) {
while (x->left != nullptr) {
x = x->left;
}
return x;
}
//최댓값 찾기
NodePtr tree_maximum(NodePtr x) {
while (x->right != nullptr) {
x = x->right;
}
return x;
}
void DisplayMenuBoard() {
std::cout << " ** AVL Tree ** " << std::endl;
std::cout << " " << std::endl;
std::cout << " Menu " << std::endl;
std::cout << " 1. Insert Key " << std::endl;
std::cout << " 2. Delete Key " << std::endl;
std::cout << " 3. Show Tree " << std::endl;
std::cout << " 4. choose order " << std::endl;
std::cout << " 5. show Menu " << std::endl;
std::cout << " 6. clear Display " << std::endl;
std::cout << " 7. exit " << std::endl;
std::cout << std::endl;
}
void SelectMenu() {
DisplayMenuBoard();
int i = -1;
while (i != 8) {
std::cout << "(show Menu : 5) --> select : ";
std::cin >> i;
switch (i) {
case 1:
Insert_helper();
break;
case 2:
Delete_helper();
break;
case 3:
print_helper(root, "", true);
break;
case 4:
Order_helper();
break;
case 5:
DisplayMenuBoard();
break;
case 6:
system("cls");
DisplayMenuBoard();
break;
case 7:
return;
default:
std::cout << " !!! Wrong entered !!!\n"
<< std::endl;
}
}
}
void Insert_helper() {
int item;
std::cout << "Key to insert : ";
std::cin >> item;
if (IsKey(item)) {
std::cout << "!!! " << item << " is already exists !!!\n";
return;
}
this->root = Insert(this->root, item);
return;
}
void Delete_helper() {
int item;
std::cout << "Key to delete : ";
std::cin >> item;
if (!IsKey(item)) {
std::cout << "!!! " << item << " is not exists !!!\n";
return;
}
this->root = Delete(this->root, item);
return;
}
void Order_helper() {
int i;
std::cout << " == Order Menu ==" << std::endl;
std::cout << " 1. PreOrder" << std::endl;
std::cout << " 2. InOrder" << std::endl;
std::cout << " 3. PostOrder" << std::endl;
std::cout << " 4. exit" << std::endl;
std::cout << " --> select : ";
std::cin >> i;
switch (i) {
case 1:
Preorder(this->root);
std::cout << std::endl;
break;
case 2:
Inorder(this->root);
std::cout << std::endl;
break;
case 3:
Postorder(this->root);
std::cout << std::endl;
break;
case 4:
return;
default:
std::cout << " !!! Wrong enter !!!\n"
<< std::endl;
break;
}
return;
}
};
int main() {
AVLTREE tree;
tree.SelectMenu();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment