AVL트리
모든 노드에 대해서 왼쪽 부분 트리와 오른쪽 부분 트리의 높이 차가 1 이하인 이진 탐색 트리
트리의 균형 상태: 균형 인수(왼쪽 부분 트리의 높이 -오른쪽 부분 트리의 높이)가 1,0,-1을 만족
트리의 불균형 상태: 균형 인수가 1 초과 or -1 미만
시간복잡도
한 레벨 씩 내려가며 삽입,삭제 연산 (높이 시간) ->
균형 인수(balance) 깨지는 것 발견 (상수 시간) ->
회전(Rotation) 처리 (상수 시간) -> AVL 트리의 연산은 O(logn)
// AVL 트리의 높이는 O(logn)
코딩 테스트 예시
size_field: [1:1], [2:2], [3:4], [4:1], [5:12], [6:2], [7:1], [8:7], [9:1], [10:4], [11:2], [12:1]
// [키 값: 서브 트리의 노드 개수]
#include <stdio.h> #include <stdlib.h> typedef struct AVLNode { int key; int size_field; int height; int balance; struct AVLNode* left; struct AVLNode* right; }AVLNode; typedef AVLNode* AVLNode_ptr; // MAX 함수 int MAX(int a, int b) { return a > b ? a : b; } // 트리의 높이 구하기 int get_height(AVLNode_ptr T) { if (T) { // 트리의 높이 = MAX(오른쪽 서브트리의 높이, 왼쪽 서브트리의 높이) +1 int tmp = MAX(get_height(T->left), get_height(T->right)); return 1 + tmp; } else return 0; } // 노드의 균형인수(왼쪽 서브트리의 높이 - 오른쪽 서브트리의 높이) 구하기 int get_balance(AVLNode_ptr T) { if (T) return get_height(T->left) - get_height(T->right); } // 노드 생성 함수 AVLNode_ptr create_node(int key) { AVLNode_ptr node = (AVLNode_ptr)malloc(sizeof(AVLNode)); node->key = key; node->size_field = node->balance = node->height = 0; // update 함수에서 일괄 처리함 node->left = node->right = NULL; return node; } // 오른쪽으로 회전시키는 함수 (왼쪽 -> 오른쪽) // LL과 LR,RL에 쓰임 AVLNode_ptr rotate_right(AVLNode_ptr parent) { AVLNode_ptr child = parent->left; parent->left = child->right; // child의 서브 트리 한 쪽을 parent가 가져감 child->right = parent; // 오른쪽 회전 return child; } // 왼쪽으로 회전시키는 함수 (오른쪽 -> 왼쪽) // RR과 LR,RL에 쓰임 AVLNode_ptr rotate_left(AVLNode_ptr parent) { AVLNode_ptr child = parent->right; parent->right = child->left; // child의 서브 트리 한 쪽을 parent가 가져감 child->left = parent; // 왼쪽 회전 return child; } // AVL 트리 삽입 AVLNode_ptr insert_node(AVLNode_ptr T, int key) { // 이진 탐색 트리의 노드 추가 수행 if (T == NULL) return create_node(key); if (key < T->key) T->left = insert_node(T->left, key); else if (key > T->key) T->right = insert_node(T->right, key); else // 동일한 키는 허용하지 않음 return T; // 노드의 균형인수 계산 int balance = get_balance(T); /* * 회전 (삽입 시 불균형이 발생하면 진행) - X: 불균형이 탐지된 가장 가까운 조상 노드 - LL 타입 처리 X 기준으로 (왼쪽 -> 오른쪽 회전) - RR 타입 처리 X 기준으로 (오른쪽 -> 왼쪽 회전) - LR 타입 처리 X의 왼쪽 자식 기준으로(오른쪽 -> 왼쪽 회전) -> X 기준으로 (왼쪽 -> 오른쪽 회전) - RL 타입 처리 X의 오른쪽 자식 기준으로 (왼쪽 -> 오른쪽 회전) -> X 기준으로 (오른쪽 -> 왼쪽 회전) */ // LL 타입 처리 if (balance > 1 && key < T->left->key) return rotate_right(T); // RR 타입 처리 if (balance < -1 && key > T->right->key) return rotate_left(T); // LR 타입 처리 if (balance > 1 && key > T->left->key) { T->left = rotate_left(T->left); return rotate_right(T); } // RL 타입 처리 if (balance < -1 && key < T->right->key) { T->right = rotate_right(T->right); return rotate_left(T); } return T; } // 트리에 size_field(부분트리에 속한 노드의 개수), balence(균형인수) 부여하기 // postorder 응용해서 제작함 void update(AVLNode_ptr T) { if (T) { update(T->left); update(T->right); // 잎 노드 if ((T->left == NULL) && (T->right == NULL)) { T->size_field = 1; T->height = 1; T->balance = 0; } // 내부 노드 else { if ((T->left != NULL) && (T->right != NULL)) { T->size_field = 1 + (T->left->size_field) + (T->right->size_field); T->height = 1 + MAX(T->left->height, T->right->height); T->balance = (T->left->height) - (T->right->height); } else if ((T->left != NULL) && (T->right == NULL)) { T->size_field = 1 + (T->left->size_field); T->height = 1 + (T->left->height); T->balance = (T->left->height) - 0; } else { T->size_field = 1 + (T->right->size_field); T->height = 1 + (T->right->height); T->balance = 0 - (T->right->height); } } } } // 전위 순회 함수 void preorder(AVLNode_ptr T) { if (T) { printf("[%d:%d,%d] ", T->key, T->size_field, T->balance); preorder(T->left); preorder(T->right); } } int main(void) { AVLNode_ptr root = NULL; root = insert_node(root, 8); root = insert_node(root, 9); root = insert_node(root, 10); root = insert_node(root, 2); root = insert_node(root, 1); root = insert_node(root, 5); root = insert_node(root, 3); root = insert_node(root, 6); root = insert_node(root, 4); root = insert_node(root, 7); root = insert_node(root, 11); root = insert_node(root, 12); update(root); // 각 노드에 서브트리의 노드 개수와 균형인수 부여하기 printf("■ 전위 순회로 AVL 트리 구조 파악 (키:서브트리의 노드 개수, 균형인수)\n\n"); preorder(root); printf("\n"); return 0; }