- AVL 트리
AVL 트리는 Adelson - Velskii와 Landis에 의해 제안된 트리로 각 노드에서 왼쪽 서브트리의 높이와 오른쪽 서브트리의 높이 차리가 1 이하인 이진 탐색 트리를 말한다. 이 트리는 트리가 비균형 상태로 되면 스스로 노드들을 재배치하여 균형 상태로 만든다. AVL 틀는 항상 균형 트리를 보장하기 때문에 의 탐색 시간을 보장한다. 삽입과 삭제 연산도
시간 안에 할 수 있다.
AVL 트리도 탐색에서는 일반 이진 탐색 트리의 탐색 연산과 동일하다. 따라서 시간 복잡도는 이다. AVL 트리에서 균형이 깨질 수 있는 연산은 삽입과 삭제 연산이다.
- AVL 트리의 삽입 연산
이진 탐색 트리에서 노드가 삽입되면 삽입되는 위치에서 루트까지의 경로에 있는 모든 조상 노드들의 균형 인수가 영향을 받는다. 따라서 불균형 상태(균형 인수가 2) 로 변한 가장 가까운 조상 노드의 서브트리들에 대하여 다시 균형을 잡아야 한다. 그 외의 다른 노드들은 변경할 필요가 없다.
AVL 트리에서 균형이 깨지는 경우는 다음의 4가지의 타입이 있다. 새로 삽입된 노드 N로 부터 가장 가가우면서 균형 인수가 가 된 조상 도드를 A라고 하자.
- LL 타입 : N이 A의 왼쪽 서브트리의 왼쪽 서브트리에 삽입된다.
- LR 타입 : N이 A의 왼쪽 서브트리의 오른쪽 서브트리에 삽입된다.
- RR 타입 : N이 오른쪽 서브트리의 오른쪽 서브트리에 삽입된다.
- RL 타입 : N이 오른쪽 서브트리의 왼쪽 서브트리에 삽입된다.
LL 과 RR 은 대칭이고 역시 LR 과 RL 도 대칭이다. 이제 트리를 다시 균형시키자. 다음은 각각의 경우에 대하여 균형 트리로 다시 만드는 방법이다.
- LL 회전 : A부터 N까지의 경로상의 노드들을 오른쪽으로 회전시킨다.
- LR 회전 : A부터 N까지의 경로상의 노드들을 왼쪽-오른쪽으로 회전 시킨다.
- RR 회전 : A부터 N까지의 경로상의 노드들을 왼쪽으로 회전시킨다.
- RL 회전 : A부터 N까지의 경로상의 노드들을 오른쪽-왼쪽으로 회전시킨다.
rotate_LL(A)
B = A의 왼쪽 자식
B의 오른쪽 자식을 A의 왼쪽 자식으로 만든다.
A를 B의 오른쪽 자식 노드로 만든다.
rotate_RR(A)
B = A의 오른쪽 자식
B의 왼쪽 자식을 A의 오른쪽 자식으로 만든다.
A를 B의 왼쪽 자식 노드로 만든다.
| AVL 트리에서의 이중 회전 알고리즘
rotate_RL(A)
B = A의 오른쪽 자식
rotate_LL(B)가 반환하는 노드를 A의 오른쪽 자식으로 만든다.
rotate_RR(A)
rotate_LR(A)
B = A의 오른쪽 자식
rotate_RR(B)가 반환하는 노드를 A의 오른쪽 자식으로 만든다.
rotate_LL(A)
#pragma once
#ifndef ___AVLTree
#define ___AVLTree
// AVLTree.h : AVL 트리 클래스 CAVLTree
#include "BinSrchTree.h"
class AVLTree : public BinSrchTree {
public:
// 노드의 균형인수를 반환
int getHeightDiff(BinaryNode* node) {
if (node == NULL) return 0;
int hLeft = getHeight(node->getLeft());
int hRight = getHeight(node->getRight());
return hLeft - hRight;
}
// LL 회전 함수
BinaryNode* rotateLL(BinaryNode* parent) {
BinaryNode* child = parent->getLeft();
parent->setLeft(child->getRight());
child->setRight(parent);
return child;
}
// RR 회전 함수
BinaryNode* rotateRR(BinaryNode* parent) {
BinaryNode* child = parent->getRight();
parent->setRight(child->getLeft());
child->setLeft(parent);
return child;
}
// RL 회전 함수
BinaryNode* rotateRL(BinaryNode* parent) {
BinaryNode* child = parent->getRight();
parent->setRight(rotateLL(child));
return rotateRR(parent);
}
// LR 회전 함수
BinaryNode* rotateLR(BinaryNode* parent) {
BinaryNode* child = parent->getLeft();
parent->setLeft(rotateRR(child));
return rotateLL(parent);
}
// 트리를 균형트리로 만든다
BinaryNode* reBalance(BinaryNode* parent) {
int hDiff = getHeightDiff(parent);
if (hDiff > 1) {
if (getHeightDiff(parent->getLeft()) > 0)
parent = rotateLL(parent);
else parent = rotateLR(parent);
}
else if (hDiff < -1) {
if (getHeightDiff(parent->getRight()) < 0)
parent = rotateRR(parent);
else parent = rotateRL(parent);
}
return parent;
}
//AVL 트리의 삽입 연산
void insert(int data) {
if (isEmpty()) root = new BinaryNode(data);
else root = insertAVL(root, data);
}
BinaryNode* insertAVL(BinaryNode* parent, int data) {
if (data < parent->getData()) {
if (parent->getLeft() != NULL)
parent->setLeft(insertAVL(parent->getLeft(), data));
else
parent->setLeft(new BinaryNode(data));
return reBalance(parent);
}
else if (data > parent->getData()) {
if (parent->getRight() != NULL)
parent->setRight(insertAVL(parent->getRight(), data));
else
parent->setRight(new BinaryNode(data));
return reBalance(parent);
}
else {
printf("중복된 키 에러\n");
return NULL;
}
}
};
#endif // !___AVLTree
'Programming > DS SorceCode' 카테고리의 다른 글
HashRecord.h : 해시 맵을 위한 keyed Record 클래스 (0) | 2019.04.06 |
---|---|
해싱 (0) | 2019.04.06 |
Search.h : 다양한 탐색 함수를 포함함 헤더 (0) | 2019.04.04 |
Sorting.h : 다양한 정렬을 포함한 헤더 (0) | 2019.04.04 |
기수 정렬 프로그램 (0) | 2019.04.04 |