AVL Tree
AVL Tree
Balanced Tree 라고도 한다. Adelson-Velsky and Landis가 발명한 트리이다. 스스로 균형을 잡는 이진 탐색 트리이다.
- 사용 이유 : 이진 검색 트리의 연산은 세 가지가 있다. 검색, 삽입, 삭제. 한 노드의 위치를 찾아야 그 노드 자리에 삽입하거나 삭제할 수 있기 때문에 검색 연산이 핵심이다. AVL TREE 검색연산의 시간 복잡도는 $O\left(log n \right)$로 다른 자료구조에 비해 속도가 빠르다. 그렇기 때문에 balanced tree중 하나인 AVL TREE를 사용한다.
- 특징 : 모든 노드에 대해, 두 자식 서브트리의 높이는 항상 최대 1만큼 차이난다. -> 코드 구현의 핵심이다.
- 구현 설계 : 삽입과 삭제 연산은 재귀적으로 구현하기.
구현
- class NODE()
- 각 노드는 key, left, right, height, bf를 갖는다. 이진 검색 트리와 다른점은 AVL TREE에 노드가 생성되어 삽일될 때, 해당 노드의 왼쪽, 오른쪽 자식 노드 또한 NIL 노드로 생성이 되도록 구현한다.
- 이유는 높이 계산시 처음 0으로 초기화 되고 다음 높이 계산은 해당 노드의 $max\left(왼쪽 자식 노드의 높이 - 오른쪽 자식 노드의 높이 \right)$를 사용하기 때문이다. 오른쪽 자식 노드의 높이를 구하기 위해서는 해당 노드의 자식 노드들이 Node()로 새로운 노드로 할당되어야 height 속성을 가져올 수 있기 때문이다.
- height : 초기값 0. $1 + max\left(왼쪽 자식 노드의 높이 - 오른쪽 자식 노드의 높이 \right)$
- balanced factor : $|왼쪽 자식 노드의 높이 - 오른쪽 자식 노드의 높이|$
class Node: def __init__(self): self.key = None # 이진 검색 트리에서 해당 노드의 key값 self.left = None self.right = None self.parent = None self.height = -1 self.bf = 0 def setKey(self,key): self.key = key def disconnect(self): self.key = None self.left = None self.right = None self.height = -1 self.bf = 0
- 각 노드는 key, left, right, height, bf를 갖는다. 이진 검색 트리와 다른점은 AVL TREE에 노드가 생성되어 삽일될 때, 해당 노드의 왼쪽, 오른쪽 자식 노드 또한 NIL 노드로 생성이 되도록 구현한다.
- $Insert\left(T,z\right)$
- 필요한 함수 :
- leftRotation(), rightRotation() : balanced factor의 절댓값이 1 이하가 아닐 때, AVLtree의 규칙을 지키기위해 사용된다.
- rebalance() : balanced factor, height 계산을 위해 사용된다.
- BST insert 연산과 동일하게 z를 삽입한다.
- AVL tree 속성에 맞춰 rotation 한다. 2-1. z원소의 조상 노드 중 가장 가까운 노드의 높이차가 2 이상이면 rotation을 시행한다.
- 필요한 함수 :
def Insert(self,x,z):
if x is None or x.key is None:
self.root = Node()
self.root.setKey(z)
self.root.left = Node()
self.root.right = Node()
self.heightUpdate(self.root)
elif x.key > z:
if x.left.key is None:
x.left.setKey(z)
x.left.left = Node()
x.left.right = Node()
x.left.parent = x
self.rebalance(x.left)
else:
self.Insert(x.left,z)
elif x.key < z:
if x.right.key is None:
x.right.setKey(z)
x.right.left = Node()
x.right.right = Node()
x.right.parent = x
self.rebalance(x.right)
else:
self.Insert(x.right,z)
else:
return "동일한 값을 삽입할 수 없습니다."
BSTREE와 달리 AVLTREE에서는 모든 노드의 자식 노드를 빈 노드로 만들어준다.
def rebalance(self,x):
print("rebalance : ",x.bf)
while x is not None:
self.heightUpdate(x)
self.balanceUpdate(x)
if x.bf == 2:
if x.left.bf > 0:
self.rightRotation(x)
else:
self.leftRotation(x.left)
self.rightRotation(x)
elif x.bf == -2:
if x.right.bf > 0:
self.rightRotation(x.right)
self.leftRotation(x)
else:
self.leftRotation(x)
self.heightUpdate(x)
x = x.parent
def heightUpdate(self,x):
if x.key:
print('height Update : ', x.key)
x.height = 1 + max(x.right.height,x.left.height)
def balanceUpdate(self,x):
if x.key:
print('balance Update : ', x.key)
x.bf = x.left.height - x.right.height
- rotation
- LL
- LR
- RR
- RL LL, RR은 단순 회전, LR, RL은 이중 회전이다.
def leftRotation(self,x):
print('leftrotation',x.key)
y = x.right
x.right = y.left
if y.left is not None:
y.left.parent = x
y.parent = x.parent
if x.parent is None:
self.root = y
elif x.key == x.parent.left.key:
x.parent.left = y
else:
x.parent.right = y
y.left = x
x.parent = y
def rightRotation(self,x):
print('rightrotation',x.key)
y = x.left
x.left = y.right
if y.right is not None:
y.right.parent = x
y.parent = x.parent
if x.parent is None:
self.root = y
elif x.key == x.parent.left.key:
x.parent.left = y
else:
x.parent.right = y
y.right = x
x.parent = y
- delete
- BST delete 연산과 동일하게 원소를 삭제한다.
- 삭제
def Delete(self,x,z):
if x.key is None:
if self.root is None: return print("<Empty Tree>")
else: return print("삭제할 node가 없습니다.")
else:
if x.key == z:
if not x.left.key and not x.right.key:
print("자식 노드 없음")
x.disconnect() # 빈 노드로 할당.
elif x.left.key and not x.right.key:
print("왼쪽 자식 노드만 있음")
x.key = x.left.key
x.left.disconnect()
elif not x.left.key and x.right.key:
print("오른쪽 자식 노드만 있음")
x.key = x.right.key
x.right.disconnect()
else:
print("자식 노드 둘 다 있음")
y = self.TreeMinimum(x.right)
x.key = y.key
y.key.disconnect()
elif x.key > z:
return self.Delete(x.left,z)
else:
return self.Delete(x.right,z)
print(x.key)
self.rebalance(x)