1. 트리
- 트리란 계층적인 구조를 표현하는 비순환 그래프입니다.
- 노드와 간선으로 구성되며, 루트 노드에서 시작하여 각 노드가 0개 이상의 자식 노드를 가집니다.
- 트리는 계층적인 데이터를 표현하거나 검색, 정렬, 삽입, 삭제 등의 연산을 수행하는 데 사용됩니다.
1.1 기본 구성 요소

- 트리의 기본 구성 요소를 이해하면 트리 자료구조를 쉽게 이해할 수 있습니다.
- 루트(Root): 트리의 최상위에 있는 노드
- 간선(Edge): 노드와 노드를 연결하는 선
- 노드(Node): 트리를 구성하는 각각의 요소
- 부모(Parent): 특정 노드의 상위 노드
- 자식(Child): 특정 노드의 하위 노드
- 단말(Leaf): 자식이 없는 말단 노드
1.2 트리의 속성
- 높이(Height): 루트에서 가장 먼 리프까지의 거리
- 깊이(Depth): 루트에서 특정 노드까지의 거리
- 레벨(Level): 같은 깊이에 있는 노드의 집합
- 차수(Degree): 노드의 자식 수
class TreeNode:
def __init__(self, value):
self.value = value
self.parent = None
self.children = []
self.height = 0
self.depth = 0
2. 이진 트리 기초
2.1 정의
- 각 노드가 최대 2개의 자식을 가지는 트리입니다.
- 왼쪽 자식과 오른쪽 자식을 명확히 구분합니다.
class BinaryTreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
2.2 이진 트리의 종류
2.2.1 완전 이진 트리(Complete Binary Tree)
- 마지막 레벨을 제외한 모든 레벨이 완전히 채워진 이진 트리를 의미합니다.
- 마지막 레벨은 왼쪽부터 순차적으로 채워져 있습니다.
- 힙(Heap)이 대표적인 완전 이진 트리입니다.
2.2.2 정 이진 트리(Full Binary Tree)
- 모든 노드가 0개 또는 2개의 자식을 가지는 이진 트리입니다.
- 자식이 있다면 반드시 2개를 가져야 합니다.
2.2.3 포화 이진 트리(Perfect Binary Tree)
- 모든 레벨이 완전히 채워진 이진 트리입니다.
- 노드 수가 2^k - 1개 (k는 트리의 높이)입니다.
3. 이진 트리 순회
3.1 깊이 우선 탐색(DFS)
- 깊이 우선 탐색의 종류로 전위 순회, 중위 순회, 후위 순회가 있습니다.
- 루트 노드를 언제 방문하느냐에 따라 순회 방법이 달라집니다.
- 전위 순회: 루트 → 왼쪽 → 오른쪽
- 중위 순회: 왼쪽 → 루트 → 오른쪽
- 후위 순회: 왼쪽 → 오른쪽 → 루트
- 재귀 함수를 사용하여 구현합니다.
3.1.1 전위 순회(Preorder)
- 순서: 루트 → 왼쪽 → 오른쪽
- 루트를 먼저 방문합니다.
def preorder(node):
if node:
print(node.value) # 루트
preorder(node.left) # 왼쪽
preorder(node.right) # 오른쪽
3.1.2 중위 순회(Inorder)
- 순서: 왼쪽 → 루트 → 오른쪽
- 이진 탐색 트리에서 정렬된 순서로 노드 방문합니다.
def inorder(node):
if node:
inorder(node.left) # 왼쪽
print(node.value) # 루트
inorder(node.right) # 오른쪽
3.1.3 후위 순회(Postorder)
- 순서: 왼쪽 → 오 른쪽 → 루트
- 자식 노드부터 처리하는 경우에 사용합니다.
def postorder(node):
if node:
postorder(node.left) # 왼쪽
postorder(node.right) # 오른쪽
print(node.value) # 루트
3.2 너비 우선 탐색(BFS)
- 레벨 순서대로 노드를 방문합니다.
- 큐를 사용하여 구현합니다.
from collections import deque
def bfs(root):
if not root:
return
queue = deque([root])
while queue:
node = queue.popleft()
print(node.value)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)