You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
코딩테스트에서는 이진트리가 무조건 출제!
다른 트리가 합쳐지면 오래 걸림 → 빠른 포기 권장
1.2 일상 속 트리의 예
예시
설명
가계도
조상-자손 관계
회사 조직도
상사-부하 관계
파일 시스템
폴더-파일 계층 구조
HTML DOM
태그의 부모-자식 관계
토너먼트 대진표
경기 순서와 결과
1.3 트리 vs 그래프
특성
트리 (Tree)
그래프 (Graph)
사이클
없음
있을 수 있음
루트
있음 (하나)
없음
방향성
있음 (위→아래)
있거나 없음
부모-자식
명확함
없음
노드 간 경로
유일함
여러 개 가능
2. 트리 용어
2.1 용어 도해
┌───────────┐
│ A │ ← 루트 노드 (Root)
│ (깊이 0) │ 레벨 0
└─────┬─────┘
│
┌─────────────┼─────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ B │ │ C │ │ D │ ← 내부 노드
│ (깊이 1) │ │ (깊이 1) │ │ (깊이 1) │ 레벨 1
└─────┬─────┘ └───────────┘ └─────┬─────┘
│ │
┌─────┴─────┐ ┌─────┴─────┐
│ │ │ │
┌─────▼─────┐┌────▼────┐ ┌─────▼─────┐┌────▼────┐
│ E ││ F │ │ G ││ H │
│ (깊이 2) ││(깊이 2) │ │ (깊이 2) ││(깊이 2) │ ← 단말 노드
└───────────┘└─────────┘ └───────────┘└─────────┘ (Leaf)
레벨 2
트리의 높이 (Height) = 2
2.2 용어 정리표
용어
영문
설명
예시 (위 그림 기준)
루트 노드
Root Node
트리의 최상단 노드 (부모가 없음)
A
단말 노드
Leaf Node / Terminal Node
자식이 없는 최하단 노드
E, F, C, G, H
내부 노드
Internal Node
루트도 단말도 아닌 중간 노드
B, D
부모 노드
Parent Node
자식이 있는 노드
A는 B,C,D의 부모
자식 노드
Child Node
부모의 하위 노드
B,C,D는 A의 자식
형제 노드
Sibling Node
같은 부모를 가진 노드들
B, C, D는 형제
조상 노드
Ancestor Node
루트까지의 경로에 있는 노드들
E의 조상: B, A
자손 노드
Descendant Node
해당 노드 아래의 모든 노드
A의 자손: B,C,D,E,F,G,H
차수
Degree
노드가 가진 자식 수
A의 차수: 3, B의 차수: 2
깊이
Depth
루트부터의 거리 (간선 수)
E의 깊이: 2
레벨
Level
같은 깊이의 노드 집합
레벨 1: B, C, D
높이
Height
트리의 최대 깊이
높이: 2
서브트리
Subtree
트리의 부분 집합 (그 자체도 트리)
B를 루트로 하는 서브트리
2.3 차수 (Degree)
차수 = 해당 노드가 가지고 있는 자식 노드의 수
예시:
- A의 차수: 3 (B, C, D)
- B의 차수: 2 (E, F)
- C의 차수: 0 (단말 노드)
- 트리의 차수: 노드 중 최대 차수 = 3
이진 트리: 모든 노드의 차수가 2 이하인 트리
3. 트리의 특징
3.1 5가지 핵심 특징
┌─────────────────────────────────────────────────────────────────┐
│ 트리의 5가지 핵심 특징 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 부모-자식 관계 │
│ → 트리는 부모 노드와 자식 노드의 관계로 표현된다 │
│ │
│ 2. 루트 노드 │
│ → 트리의 최상단 노드를 루트 노드(Root Node)라 한다 │
│ │
│ 3. 단말 노드 │
│ → 트리의 최하단 노드(자식이 없는 노드)를 단말 노드라 한다 │
│ │
│ 4. 서브트리 │
│ → 트리에서 일부를 떼어내도 트리 구조이며, 이를 서브트리라 함│
│ │
│ 5. 계층 구조 │
│ → 파일 시스템과 같이 계층 구조를 이루고, │
│ 정렬된 데이터를 다루기에 적합하다 │
│ │
└─────────────────────────────────────────────────────────────────┘
3.2 트리의 성질
노드가 N개인 트리는 N-1개의 간선을 가진다
루트에서 특정 노드까지의 경로는 유일하다
임의의 두 노드 사이의 경로도 유일하다
트리는 사이클(순환)이 없는 연결 그래프이다
4. 트리의 종류
4.1 종류 비교표
종류
설명
특징
일반 트리
차수 제한 없음
자식 수 제한 없음
이진 트리
차수가 최대 2
왼쪽, 오른쪽 자식만
이진 탐색 트리
정렬된 이진 트리
왼쪽 < 부모 < 오른쪽
완전 이진 트리
왼쪽부터 채워진 이진 트리
힙 구현에 사용
포화 이진 트리
모든 레벨이 꽉 찬 이진 트리
노드 수 = 2^h - 1
균형 이진 트리
좌우 높이 차이 <= 1
AVL, 레드-블랙 트리
4.2 이진 트리 종류 시각화
완전 이진 트리 (Complete Binary Tree)
- 마지막 레벨을 제외하고 모든 레벨이 완전히 채워짐
- 마지막 레벨은 왼쪽부터 채워짐
1 ✓ 완전 이진 트리
/ \
2 3
/ \ /
4 5 6
포화 이진 트리 (Full/Perfect Binary Tree)
- 모든 레벨이 완전히 채워짐
- 노드 수 = 2^(h+1) - 1 (h: 높이)
1 ✓ 포화 이진 트리
/ \
2 3
/ \ / \
4 5 6 7
편향 이진 트리 (Skewed Binary Tree)
- 한쪽 방향으로만 노드가 있음
- 최악의 경우 (사실상 연결 리스트)
1 1
\ /
2 2
\ /
3 3
\ /
4 4
(우편향) (좌편향)
5. 이진 트리
5.1 이진 트리란?
모든 노드의 차수가 2 이하인 트리
각 노드는 최대 2개의 자식을 가짐 (왼쪽, 오른쪽)
왼쪽 자식과 오른쪽 자식은 구분됨
5.2 이진 트리의 속성
속성
공식
설명
최대 노드 수
2^(h+1) - 1
높이 h인 이진 트리의 최대 노드 수
레벨 l의 최대 노드 수
2^l
레벨 l에 있을 수 있는 최대 노드 수
리프 노드 수
n0 = n2 + 1
차수 0인 노드 = 차수 2인 노드 + 1
최소 높이
log2(n+1) - 1
n개 노드의 이진 트리 최소 높이
5.3 배열로 이진 트리 표현
완전 이진 트리는 배열로 효율적으로 표현 가능
1 인덱스 관계:
/ \ - 부모: (i-1) // 2
2 3 - 왼쪽 자식: 2*i + 1
/ \ / \ - 오른쪽 자식: 2*i + 2
4 5 6 7
인덱스: 0 1 2 3 4 5 6
배열: [1, 2, 3, 4, 5, 6, 7]
# 배열 인덱스로 이진 트리 관계 표현defparent(i):
return (i-1) //2defleft_child(i):
return2*i+1defright_child(i):
return2*i+2# 예시tree= [1, 2, 3, 4, 5, 6, 7]
# 인덱스 1의 부모print(tree[parent(1)]) # tree[0] = 1# 인덱스 1의 왼쪽 자식print(tree[left_child(1)]) # tree[3] = 4# 인덱스 1의 오른쪽 자식print(tree[right_child(1)]) # tree[4] = 5
6. 이진 탐색 트리 (BST)
6.1 이진 탐색 트리란?
이진 탐색 트리(Binary Search Tree, BST)는 정렬된 이진 트리입니다.
핵심 규칙: 왼쪽 자식 < 부모 < 오른쪽 자식
6.2 BST의 특성
이진 탐색 트리 예시:
8
/ \
3 10
/ \ \
1 6 14
/ \ /
4 7 13
특성:
1. 왼쪽 서브트리의 모든 값 < 루트 값
2. 오른쪽 서브트리의 모든 값 > 루트 값
3. 왼쪽, 오른쪽 서브트리도 각각 BST
예시 검증:
- 노드 8: 왼쪽(3,1,6,4,7) 모두 < 8 ✓
오른쪽(10,14,13) 모두 > 8 ✓
- 노드 3: 왼쪽(1) < 3 ✓
오른쪽(6,4,7) > 3 ✓
6.3 BST vs 일반 이진 트리
특성
이진 트리
이진 탐색 트리
차수
최대 2
최대 2
정렬
없음
왼쪽 < 부모 < 오른쪽
탐색
O(n)
O(log n) 평균
삽입
어디든 가능
규칙에 따라 위치 결정
중위 순회
의미 없음
정렬된 순서 출력
6.4 BST 주요 연산
6.4.1 탐색 (Search)
defsearch_bst(node, target):
""" BST에서 값 탐색 - target이 현재 노드보다 작으면 왼쪽으로 - target이 현재 노드보다 크면 오른쪽으로 """ifnodeisNone:
returnNone# 못 찾음iftarget==node.val:
returnnode# 찾음eliftarget<node.val:
returnsearch_bst(node.left, target) # 왼쪽 탐색else:
returnsearch_bst(node.right, target) # 오른쪽 탐색
6.4.2 삽입 (Insert)
definsert_bst(node, val):
""" BST에 값 삽입 - 탐색과 같은 방식으로 위치를 찾아서 삽입 """ifnodeisNone:
returnTreeNode(val) # 새 노드 생성ifval<node.val:
node.left=insert_bst(node.left, val)
else:
node.right=insert_bst(node.right, val)
returnnode
6.4.3 삭제 (Delete)
defdelete_bst(node, val):
""" BST에서 값 삭제 - 경우 1: 리프 노드 → 그냥 삭제 - 경우 2: 자식 1개 → 자식으로 대체 - 경우 3: 자식 2개 → 오른쪽 서브트리의 최소값으로 대체 """ifnodeisNone:
returnNoneifval<node.val:
node.left=delete_bst(node.left, val)
elifval>node.val:
node.right=delete_bst(node.right, val)
else:
# 찾음 - 삭제 수행ifnode.leftisNone:
returnnode.right# 경우 1, 2elifnode.rightisNone:
returnnode.left# 경우 2# 경우 3: 오른쪽 서브트리의 최소값 찾기min_node=find_min(node.right)
node.val=min_node.valnode.right=delete_bst(node.right, min_node.val)
returnnodedeffind_min(node):
"""가장 왼쪽 노드 (최소값) 찾기"""whilenode.left:
node=node.leftreturnnode
7. 트리 순회
7.1 순회 방식 개요
트리의 모든 노드를 방문하는 방법은 크게 4가지가 있습니다.
순회 방식
영문
순서
기억법
전위 순회
Preorder
루트 → 왼쪽 → 오른쪽
VLR (Visit first)
중위 순회
Inorder
왼쪽 → 루트 → 오른쪽
LVR (Visit middle)
후위 순회
Postorder
왼쪽 → 오른쪽 → 루트
LRV (Visit last)
레벨 순회
Level-order
레벨별 왼쪽→오른쪽
BFS 방식
7.2 순회 예시
예시 트리:
1
/ \
2 3
/ \ / \
4 5 6 7
전위 순회 (Preorder): 1 → 2 → 4 → 5 → 3 → 6 → 7
- 루트를 먼저 방문
- "부모 → 왼쪽 자식 → 오른쪽 자식"
중위 순회 (Inorder): 4 → 2 → 5 → 1 → 6 → 3 → 7
- 왼쪽 서브트리 먼저, 루트, 오른쪽 서브트리
- BST에서는 정렬된 순서!
후위 순회 (Postorder): 4 → 5 → 2 → 6 → 7 → 3 → 1
- 자식들을 먼저 방문
- 트리 삭제, 폴더 크기 계산에 유용
레벨 순회 (Level-order): 1 → 2 → 3 → 4 → 5 → 6 → 7
- 위에서 아래로, 왼쪽에서 오른쪽
- BFS 방식
7.3 순회 구현 (재귀)
classTreeNode:
def__init__(self, val=0, left=None, right=None):
self.val=valself.left=leftself.right=rightdefpreorder(node, result=None):
"""전위 순회: 루트 → 왼쪽 → 오른쪽"""ifresultisNone:
result= []
ifnode:
result.append(node.val) # 1. 루트 방문preorder(node.left, result) # 2. 왼쪽 서브트리preorder(node.right, result) # 3. 오른쪽 서브트리returnresultdefinorder(node, result=None):
"""중위 순회: 왼쪽 → 루트 → 오른쪽"""ifresultisNone:
result= []
ifnode:
inorder(node.left, result) # 1. 왼쪽 서브트리result.append(node.val) # 2. 루트 방문inorder(node.right, result) # 3. 오른쪽 서브트리returnresultdefpostorder(node, result=None):
"""후위 순회: 왼쪽 → 오른쪽 → 루트"""ifresultisNone:
result= []
ifnode:
postorder(node.left, result) # 1. 왼쪽 서브트리postorder(node.right, result) # 2. 오른쪽 서브트리result.append(node.val) # 3. 루트 방문returnresult
7.4 순회 구현 (반복 - 스택 사용)
defpreorder_iterative(root):
"""전위 순회 - 반복 (스택 사용)"""ifnotroot:
return []
result= []
stack= [root]
whilestack:
node=stack.pop()
result.append(node.val)
# 오른쪽 먼저 push (왼쪽이 먼저 pop되도록)ifnode.right:
stack.append(node.right)
ifnode.left:
stack.append(node.left)
returnresultdefinorder_iterative(root):
"""중위 순회 - 반복 (스택 사용)"""result= []
stack= []
current=rootwhilestackorcurrent:
# 왼쪽 끝까지 이동whilecurrent:
stack.append(current)
current=current.left# 방문current=stack.pop()
result.append(current.val)
# 오른쪽으로 이동current=current.rightreturnresultdefpostorder_iterative(root):
"""후위 순회 - 반복 (스택 2개 사용)"""ifnotroot:
return []
result= []
stack1= [root]
stack2= []
whilestack1:
node=stack1.pop()
stack2.append(node)
ifnode.left:
stack1.append(node.left)
ifnode.right:
stack1.append(node.right)
whilestack2:
result.append(stack2.pop().val)
returnresult
defmaxDepth(root):
""" 이진 트리의 최대 깊이 깊이 = 루트에서 가장 먼 리프까지의 노드 수 """ifnotroot:
return0left_depth=maxDepth(root.left)
right_depth=maxDepth(root.right)
returnmax(left_depth, right_depth) +1
deflowestCommonAncestor(root, p, q):
""" 두 노드의 가장 가까운 공통 조상 찾기 """ifnotrootorroot==porroot==q:
returnrootleft=lowestCommonAncestor(root.left, p, q)
right=lowestCommonAncestor(root.right, p, q)
ifleftandright:
returnroot# p와 q가 각각 좌우에 있음returnleftifleftelseright
1. 재귀적 사고
- 트리 문제의 대부분은 재귀로 해결
- "이 노드에서 무엇을 해야 하는가?"를 먼저 생각
2. 순회 방식 선택
- 부모 먼저 처리 → 전위 순회
- 정렬 순서 필요 → 중위 순회
- 자식 먼저 처리 → 후위 순회
- 레벨별 처리 → 레벨 순회 (BFS)
3. BST 특성 활용
- 값 비교로 탐색 방향 결정
- 중위 순회 = 정렬된 순서