경로
라고 한다.사이클
이라고 한다.사이클
트리는 계층적인 구조로 되어 있는 자료구조이다.
운영체제에서 파일을 분류하기 위해 사용하는 디렉토리가 트리 구조의 대표적인 예시 !
h
라고 하면, 정점의 개수는 2^h - 1
개 이다.DFS방식 구현
def preorder(tree) :
# 순회를 한 결과 방문한 노드들을 순서대로 담고 있는 리스트
# result에 값을 추가한다 = 현재 노드를 방문한다.
result = []
result.append(tree.index)
if tree.left != None:
result = result + preorder(tree.left)
if tree.right != None:
result = result + preorder(tree.right)
return result
def inorder(tree) :
result = []
if tree.left != None:
result = result + inorder(tree.left)
result.append(tree.index)
if tree.right != None:
result = result + inorder(tree.right)
return result
def postorder(tree) :
result = []
if tree.left != None:
result = result + postorder(tree.left)
if tree.right != None:
result = result + postorder(tree.right)
result.append(tree.index)
return result
방문 순서 : 1 - 2 - 3 - 4 - 5 - 6 - 7
BFS는 큐 자료구조를 이용하여 구현한다.
현재 정점과 이웃한 정점일수록 먼저 방문해야 하므로 FIFO 자료구조인 큐를 이용해야 한다.
BFS방식 구현
from queue import Queue
def BFS(tree) :
q = Queue()
q.put(tree)
result = []
#q에 뭔가 들어있다면 계속 반복을 한다. -> 더이상 노드 없을 때 종료
while len(q.queue) > 0:
cur = q.get()
if cur == None :
continue
result.append(cur.index)
q.put(cur.left)
q.put(cur.right)
return result
#Tree 클래스는 어떤 트리의 루트 노드에 대한 정보를 갖고 있다.
#루트 노드를 통해 하위 노드에 접근할 수 있으므로 전체 트리에 접근할 수 있음!
class Tree:
def __init__(self, i, l, r) :
self.index = i
self.left = l
self.right = r
#재귀적으로 동작한다.
#새로운 노드가 현재 노드의 자식으로 추가되어야 하는 경우
# -> 바로 추가
#그렇지 않다면, 자기 자식중에 새로운 노드를 받을 수 있는 노드를 탐색한다
# -> 재귀 알고리즘 도입
def addNode(self, i, l, r) :
'''
트리 내의 정점 i에 대하여 왼쪽자식을 l, 오른쪽 자식을 r로
설정해주는 함수를 작성하세요.
'''
#루트 노드에 대한 처리
if self.index == None or self.index == i:
self.index = i
self.left = Tree(l, None, None) if l != None else None
self.right = Tree(r, None, None) if r != None else None
return True
else:
flag = False
if self.left != None:
flag = self.left.addNode(i, l, r)
if flag == False and self.right != None:
flag = self.right.addNoade(i, l, r)
return flag
트리를 DFS로 순회하다 보면 언젠가 리프 노드에 도달하게 되는데,
이때 각 노드가 루트 노드로부터 얼마나 떨어져 있는지 계산할 수 있다
모든 리프 노드에 대해 깊이를 구하고, 가장 큰 값에 1을 더해 출력해주면 된다.
주어진 트리의 너비가 가장 큰 레벨과 그 레벨의 너비를 계산해야 한다.
레벨이란, 깊이가 같은 노드들의 집합을 의미하며 루트 노드부터 1로 시작한다.
같은 레벨의 노드는 같은 행에 위치해야 하고, 한 열에는 하나의 정점만 위치해야 한다.
img출처: 엘리스AI트랙
이때 가장 너비가 긴 레벨은 2이고, 그 너비는 4이다.
정점의 행은 각 정점의 깊이를 구하면서 구할 수 있다.
그렇다면 열은 ?
어떤 정점 A의 왼쪽 서브 트리의 정점들의 열이 모두 확정되었다면 비로소 A의 열도 확정지을 수 있다.
즉, 중위 순회를 이용하여 트리의 너비를 구할 수 있다.
트리 높이 구하기
def getHeight(myTree) :
#루트 노드를 포함해서, 왼쪽 서브트리와 오른쪽 서비트리를 모두 포함
#왼쪽 서브트리의 높이를 구해보고,
#오른쪽 서브트리의 높이를 구해보고,
#두 높이를 비교 => 더 높은 서브트리의 높이 + 1(루트 노드)
if myTree == None:
return 0
else:
return 1 + max(getHeight(myTree.left), getHeight(myTree.right))
트리의 너비 구하기
def inorder(tree, depth):
result = []
if tree.left != None:
result += inorder(tree.left, depth+1)
tree.setDepth(depth)
result.append(tree)
if tree.right != None:
result += inorder(tree.right, depth+1)
return result
def getWidth(myTree) :
# 반환값 형식 : (l, w)
result = inorder(myTree, 1)
# print('result:', result)
n = len(result)
#정점의 개수는 1000개 이하이다 (입력 조건)
# 깊이의 최댓값은 1000 이라고 가정
#left[i] = 깊이가 i인 모든 노드들 중에서, 가장 왼쪽에 있는 노드의 행
#right[i] = 깊이가 i인 모든 노드들 중에서, 가장 오른쪽에 있는 노드의 행
#어떤 깊이의 너비는 right[i] - left[i] 인 값
left = [1001 for i in range(1001)]
right = [-1 for i in range(1001)]
maxDepth = 0
for i in range(n):
d = result[i].depth
left[d] = min(left[d], i)
right[d] = max(right[d], i)
maxDepth = max(maxDepth, d)
ansDepth = 0
ans = 0
for i in range(1, maxDepth+1):
temp = right[i] - left[i] + 1
if ans < temp:
ansDepth = i
ans = temp
return (ansDepth, ans)*
트리 실습이 은근히 어렵다
다시 처음부터 차근차근 실습과 함께 공부해보자..!