트리구조는 배열구조 또는 자료구조 (1)의 Linked list와 비슷하게 노드(Node)라는 개념을 이용해서 구현할 수 있다. 데이터의 양이 많고 데이터의 삽입과 삭제가 유동적이면 Linked list, 데이터 양이 정해져있으며 컨트롤 할 수 있으면 배열로 구현한다.
트리구조에서 사용하는 용어를 정리해보자.
Root Node : 부모가 없는 노드이며, 트리의 가장 위에 있는 노드를 말한다. 트리구조에서는 단 한개의 루트 노드를 가진다. ( A )
Leaf Node : 말단 노드는 자식 노드가 없는 노드이다. ( G,H,I,E,J,K,L )
Sibling : 같은 부모를 가지는 노드를 말한다.
Edge : 노드와 노드를 연결하는 선을 말한다.
Degree
Depth : 루트에서 노드 까지의 간선의 개수 ( B : 1 )
Level : 특정 깊이를 가지는 노드의 집합 ( A : 1, { B, C } : 2 )
트리의 height : 트리에서 가장 깊은 Level ( 4 )
Size : 자신을 포함한 모든 자식노드의 개수 ( 트리의 size : 12, B : 6 )
트리구조는 데이터를 어떻게 삽입하고 삭제하는 것에 대해 초점이 잡힌 게 아니라, 데이터를 어떻게 표현할지에 초점이 잡혀있다는 것을 인지하는 것이 좋다.
이진트리는 하나의 노드에 최대 2개의 서브트리가 있는 노드를 의미한다.
각각의 서브트리의 노드는 부모의 왼쪽, 오른쪽 자식인지 지정된다.
전 이진 트리 ( Full binary tree )
완전 이진 트리 ( Complete binary tree )
편향 이진 트리 ( Skewed binary tree )
균형 이진 트리 ( Balanced binary tree )
모든 노드의 왼쪽과 오른쪽 서브 트리의 높이가 1이상 차이 나지 않는 구조
이진 검색 트리 ( Binary search tree )
어떤 노드(N)를 기준으로 왼쪽 서브트리의 노드의 모든 값은 노드 N의 값보다 작야아 한다.
오른쪽 서브트리 노드의 값은 노드 N의 값보다 커야한다.
층별 순회 ( levelorder traversal )
전위 순회 ( preorder traversal )
중위 순회 ( Inorder traversal )
후위 순회 ( Postorder traversal )
Python 구현 : Binary Tree
class Node:
def __init__(self,data):
self.data = data
self.left = None
self.right = Nonde
class BinaryTree:
def __init__(self):
self.root = None
## 부모노드와 자식노드들로 트리를 만든다.
def make_tree(self,node,L_node,R_node):
if self.root is None:
self.root = node
node.left = L_node
node.right = R_node
## 레벨별 순회
def levelorder(self):
# root가 없으면
if self.root is None:
return -1
else:
## 층별순회를 하기위한 Queue역할의 배열생성
Q = [self.root]
print('레벨 순회',end=' :')
while Q:
tmp = Q.pop(0)
if tmp is None:
break
Q.append(tmp.left)
Q.append(tmp.right)
print(tmp.data,end=' ')
## 전위 순회 ( Root - L - R )
def preorder(self,node):
print(node.data, end=' ')
if node.left != None: self.preorder(node.left)
if node.right != None: self.preorder(node.right)
## 중위 순회 ( L - Root - R )
def inorder(self,node):
if node.left != None: self.inorder(node.left)
print(node.data, end = ' ')
if node.right != None: self.inorder(node.right)
## 후위 순회 ( L - R - Root )
def postorder(self,node):
if node.left != None: self.postorder(node.left)
if node.right != None: self.postorder(node.right)
print(node.data,end=' ')
if __name__ == '__main__':
nodes = []
nodes.append(Node(1))
nodes.append(Node(2))
nodes.append(Node(3))
nodes.append(Node(4))
nodes.append(Node(5))
nodes.append(Node(6))
nodes.append(Node(7))
BT = BinaryTree()
for i in range(int(len(nodes)/2)):
BT.make_tree(nodes[i],nodes[2*i+1],nodes[2*i+2])
BT.levelorder()
print('\n전위순회 :',end =' ') ;BT.preorder(BT.root)
print('\n중위순회 : ',end = '') ;BT.inorder(BT.root)
print('\n후위순회 :',end=' ');BT.postorder(BT.root)
Python 구현 : binary search tree
이진탐색트리는 모든 노드에 대해 왼쪽 자식 노드들의 값이 현재 노드 값보다 작거나 같고 오른쪽 자식 노드들의 값이 현재 노드 값보다 크다는 조건이 있는 트리 구조이다.
class Node:
def __init__(self,data):
self.data = data
self.left = None
self.right = None
class BinarySearchTree:
def __init__(self):
self.root = None
# 데이터 삽입
def insert(self,data):
self.root = self.insert_data(self.root,data)
return self.root is not None
def insert_data(self,node,data):
if node is None:
node = Node(data)
else:
if data <= node.data:
node.left = insert_data(node.left,data)
else:
node.right = insert_data(node.right,data)
return node
# 데이터 탐색 ( 존재 유무 )
def find(self,data):
return self.find_data(self.root,data)
def find_data(self,root,key):
if root is None or root.data == key:
return root is not None
elif key < root.data:
return self.find_data(root.left,key)
else:
return self.find_data(root.right,key)
# 데이터 삭제
def delete(self,data):
'''
노드의 자식이 없으면 상관없지만, 노드의 자식이 하나인 경우 그 자식 노드를
삭제할 노드 위치로 옮겨준다. 노드의 자식이 두개인 경우는 ?
삭제할 노드 기준 왼쪽 서브트리 : A
삭제할 노드 기준 오른쪽 서브트리 : B
B의 가장 왼쪽 아래에 위치한 노드를 가져온다.
A의 모든 원소보다 크며 B의 나머지 원소들 보다 작기 때문이다.
'''
self.root , deleted = self.delete_value(self.root,key)
return deleted
def delete_value(self,node,key):
if node is None:
return node,False
deleted = False
if key == node.data:
deleted = True
# 자식이 둘다 있을 경우
if node.left and node.right:
#오른쪽 서브트리의 맨 왼쪽아래 노드
par , chi = node, node.right
while chi.left is not None:
par , chi = chi , chi.left
# chi이 왼쪽 맨 아래 노드 ( chi의 left에 node의 왼쪽서브트리 연결 )
chi.left = node.left
# chi 노드의 오른쪽 값들을 par.left에 연결
if par != node:
par.left = chi.right
chi.right = node.right
node = chi
#삭제할값이 노드보다 작은경우
elif key < node.data::
node.left, deleted = self.deleted_value(node.left,key)
#삭제할값이 노드보다 큰경우
else:
node.right, deleted = self.delete_value(node.right,key)
return node, deleted