아카이빙

AVL 트리

셩님 2018. 5. 29. 18:37

AVL 트리

  • 균형잡힌 이진 탐색 트리

  • 검색, 삽입, 삭제의 시간 복잡도는

  • 각각의 노드 마다 왼쪽의 서브트리의 높이와 오른쪽의 서브트리의 높이 차이(균형)가 1보다 크지 않음.


노드 클래스

class Node {
public:
int data;
int height;
Node* left;
Node* right;

Node(int data) {
this->data = data;
this->height = 1;
left = NULL;
right = NULL;
}
};

AVLTree 클래스

class AVLTree {
public:
Node* root;

AVLTree(int data) {
root = new Node(data);
}

Node* RotateLL(Node* node) {}
Node* RotateRR(Node* node) {}
Node* RotateLR(Node* node) {}
Node* RotateRL(Node* node) {}
   
int Height(Node* node) {}
int HeightDiff(Node* node) {}
void Rebalance() {}

void Insert(int data) {}
   
void Preorder(Node* root) {}
void Inorder(Node* root) {}
void Postorder(Node* root) {}
};


AVL 트리의 회전

Node* RotateLL(Node* node) {
   Node* parentNode = node;
   Node* childNode = parentNode->left;

   parentNode->left = childNode->right;
   childNode->right = parentNode;

   return childNode;
}

Node* RotateRR(Node* node) {
   Node* parentNode = node;
   Node* childNode = parentNode->right;

   parentNode->right = childNode->left;
   childNode->left = parentNode;

   return childNode;
}

Node* RotateLR(Node* node) {
   Node* parentNode = node;
   Node* childNode = parentNode->left;

   parentNode->left = RotateRR(childNode);
   return RotateLL(parentNode);
}

Node* RotateRL(Node* node) {
   Node* parentNode = node;
   Node* childNode = parentNode->right;

   parentNode->right = RotateLL(childNode);
   return RotateRR(parentNode);
}
  • AVL 트리의 회전은 크게 4가지 종류가 있다. LL, RR, LR, RR

  • LL 회전은 LL 상태(자식 노드가 왼쪽으로 연속으로 연결되어 균형이 +2 이상이 된 상태)를 보완하기 위한 회전이다.

    5
  /
3 => 3
/   / \
1                       1   5
  • RR 회전은 반대로

    1
    \
    3 => 3
\   / \
        5             1   5
  • LR회전은 LR 상태에서 왼쪽 서브트리를 기준으로 RR회전을하고, LL 상태로 만든뒤, LL 회전을 하는 과정이다.

    5                     5
  / /
1 => 3 => 3
  \   /   / \
  3                 1                         1   5
  • RL회전은 LR 회전의 반대

    1                  1
    \                 \
    5 => 3 => 3
/     \   / \
    3                       5         1   5


AVL 트리의 높이 차이(균형)

int Height(Node* node) {
   if (node == NULL) {
       return 0;
  }
   int leftHeight = Height(node->left);
   int rightHeight = Height(node->right);

   if (leftHeight > rightHeight) {
       return leftHeight + 1;
  }
   else {
       return rightHeight + 1;
  }
}

int HeightDiff(Node* node) {
   if (node == NULL) {
       return 0;
  }

   int leftHeight = Height(node->left);
   int rightHeight = Height(node->right);
   return leftHeight - rightHeight;
}


Rebalancing

void Rebalance() {
   int hDiff = HeightDiff(this->root);
   if (hDiff > 1) {
       if (HeightDiff(this->root->left) > 0) {
           this->root = RotateLL(this->root);
      }
       else {
           this->root = RotateLR(this->root);
      }
  }

   if (hDiff < -1) {
       if (HeightDiff(this->root->right) < 0) {
           this->root = RotateRR(this->root);
      }
       else {
           this->root = RotateRL(this->root);
      }
  }
}
  • 높이차이가 1보다 크면 LR이나 LL 상태이다.

    • 왼쪽서브트리의 높이차이가 0보다 크면 LL 상태이고, 아니면 LR상태

  • 높이차이가 -1보다 작으면 RR이나 RL 상태이다.

    • 오른쪽서브트리의 높이차이가 0보다 작으면 RR 상태이고, 아니면 RL상태


AVL 트리 삽입

void Insert(int data) {
   Node* parent = NULL;
   Node* cur = root;

   while (cur != NULL) {
       if (data == cur->data) {
           return;
      }

       parent = cur;

       if (cur->data > data) {
           cur = cur->left;
      }
       else {
           cur = cur->right;
      }
  }

   cur = new Node(data);

   if (parent != NULL) {
       if (data < parent->data) {
           parent->left = cur;
      }
       else {
           parent->right = cur;
      }
  }

   Rebalance();
}
  • 노드를 삽입하고 나서 리밸런싱을 한번 해준다.


트리 순회

void Preorder(Node* root) {
   cout << root->data << endl;
   if (root->left != NULL) Preorder(root->left);
   if (root->right != NULL) Preorder(root->right);
}

void Inorder(Node* root) {
   if (root->left != NULL) Inorder(root->left);
   cout << root->data << endl;
   if (root->right != NULL) Inorder(root->right);
}

void Postorder(Node* root) {
   if (root->left != NULL) Postorder(root->left);
   if (root->right != NULL) Postorder(root->right);
   cout << root->data << endl;
}


메인 함수

int main() {
AVLTree* tree = new AVLTree(1);
tree->Insert(3);
tree->Insert(5);
tree->Insert(7);
tree->Insert(9);
tree->Insert(4);

tree->Preorder(tree->root);
//tree->Inorder(tree->root);
//tree->Postorder(tree->root);

return 0;
}

'아카이빙' 카테고리의 다른 글

문자열 뒤집기 알고리즘  (0) 2018.06.03
해쉬 테이블(Hash Table)  (0) 2018.05.29
이진 탐색 트리(Binary Search Tree)  (0) 2018.05.29
하노이 타워 문제  (0) 2018.05.29
정렬된 두 배열을 병합하기  (0) 2018.05.24