Binary Tree (이어서)
이진 트리에서 수행하는 주요 연산은
- 순회 (Traversal)
- 복사 (Copy)
- 동등성 검사 (Equality Test)
- 만족 가능성(Satisfiability) 문제 해결
이렇게 네가지가 있음.
1. Binary Tree Traversals (이진 트리 순회)
트리 순회란 트리의 모든 노드를 특정한 규칙에 따라 한 번씩 방문하는 과정임.
이진 트리에서는 다음 세 가지 기본 순회 방법이 있음.
1) 전위 순회 (Preorder Traversal)
방문 순서: Root → Left Subtree → Right Subtree (V L R)
즉, 현재 노드를 먼저 처리하고 나서 왼쪽, 오른쪽으로 내려감.
void preorder(TreeNode* root) {
if (root != NULL) {
printf("%d ", root->data); // root
preorder(root->left); // left
preorder(root->right); // right
}
}
예를 들면,
A
/ \
B C
/ \ \
D E F
| 단계 | 방문 노드 | 동작 | 그림 |
| 1 | A | 루트부터 시작 | ![]() |
| 2 | B | 왼쪽 서브트리로 이동 | |
| 3 | D | B의 왼쪽 방문 (리프 노드) | |
| 4 | E | B의 오른쪽 방문 | |
| 5 | C | 루트 A의 오른쪽 이동 | |
| 6 | F | C의 오른쪽 방문 |
순서: A B D E C F
== 트리 구조를 복사하거나 저장할 때 자주 사용함.
2) 중위 순회 (Inorder Traversal)
방문 순서: Left Subtree → Root → Right Subtree (L V R)
void inorder(TreeNode* root) {
if (root != NULL) {
inorder(root->left);
printf("%d ", root->data);
inorder(root->right);
}
}
예를 들면,
A
/ \
B C
/ \ \
D E F
| 단계 | 방문 노드 | 동작 | 그림 |
| 1 | D | 왼쪽 끝까지 이동 | ![]() |
| 2 | B | D의 부모 방문 | |
| 3 | E | B의 오른쪽 자식 방문 | |
| 4 | A | 루트 방문 | |
| 5 | C | 루트 A의 오른쪽 이동 | |
| 6 | F | C의 오른쪽 방문 |
순서: D B E A C F
== 이진 탐색 트리(BST) 에서 중위 순회 결과는 오름차순 정렬이 됨.
3) 후위 순회 (Postorder Traversal)
방문 순서: Left Subtree → Right Subtree → Root (L R V)
void postorder(TreeNode* root) {
if (root != NULL) {
postorder(root->left);
postorder(root->right);
printf("%d ", root->data);
}
}
예를 들면,
A
/ \
B C
/ \ \
D E F
| 단계 | 방문 노드 | 동작 | 그림 |
| 1 | D | 왼쪽 끝까지 이동 | ![]() |
| 2 | E | B의 오른쪽 방문 | |
| 3 | B | B의 모든 자식 방문 후 B 방문 | |
| 4 | F | C의 오른쪽 방문 | |
| 5 | C | C의 모든 자식 방문 후 C 방문 | |
| 6 | A | 전체 트리의 루트 마지막 방문 |
순서: D E B F C A
== 하위 노드를 먼저 처리하고 루트를 나중에 처리해야 할 때 사용함.
트리 삭제, 수식 계산(Expression Tree) 등에 활용됨.
4) Level-order Traversal (레벨 순회)
레벨(층) 단위로 탐색하는 순회 방식.
Queue를 이용해서 구현함.
void levelorder(TreeNode* root) {
if (root == NULL) return;
Queue q;
enqueue(&q, root);
while (!isEmpty(&q)) {
TreeNode* n = dequeue(&q);
printf("%d ", n->data);
if (n->left) enqueue(&q, n->left);
if (n->right) enqueue(&q, n->right);
}
}
예를 들면,
A
/ \
B C
/ \ \
D E F
| 단계 | 방문 노드 | 동작 |
| 1 | A | 루트 (맨위) |
| 2 | B, C | 2층 (왼쪽 → 오른쪽) |
| 3 | D, E, F | 3층 (왼쪽 → 오른쪽) |
순서: A B C D E F
== 트리의 층별 구조를 파악할 때 유용함.
2. Copying Binary Trees (이진 트리 복사)
트리를 복사하려면 각 노드를 새로 생성하면서
왼쪽, 오른쪽 서브트리까지 재귀적으로 복사해야 함.
TreeNode* copy(TreeNode* root) {
if (root == NULL) return NULL;
TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
newNode->data = root->data;
newNode->left = copy(root->left);
newNode->right = copy(root->right);
return newNode;
}
- 구조와 데이터 모두 동일한 완전 복사(deep copy) 를 수행함.
- 전위 순회(preorder) 방식과 유사하게 구현됨.
3. Testing Equality (트리 동등성 검사)
두 개의 이진 트리가 같은 구조와 같은 데이터를 가지고 있는지 비교함.
int equal(TreeNode* t1, TreeNode* t2) {
if (t1 == NULL && t2 == NULL) return 1;
if (t1 == NULL || t2 == NULL) return 0;
return (t1->data == t2->data)
&& equal(t1->left, t2->left)
&& equal(t1->right, t2->right);
}
비교 로직:
- 두 노드 모두 NULL → 같음
- 하나만 NULL → 다름
- 값 비교 후 왼쪽, 오른쪽 서브트리 재귀 비교
- 완전 동일한 구조인지 판단할 때 사용함.
4. The Satisfiability Problem (만족 가능성 문제)
논리식(불 표현식, Boolean Expression)이 주어졌을 때
참이 되도록 변수에 값을 할당할 수 있는지 판별하는 문제.
즉, “이 논리식이 만족될 수 있는가?”를 묻는 문제임.
예:
(A ∨ B) ∧ (¬A ∨ C)
- A = False, B = True, C = True → 식은 참
- 따라서 satisfiable (만족 가능) 함.
트리로 표현하기
논리식을 트리 형태로 표현하면 논리 연산 트리 (Logical Expression Tree) 가 됨.
∧
/ \
∨ ∨
/ \ / \
A B ¬A C
각 노드는 연산자(∧, ∨, ¬) 또는 피연산자(A, B, C)임.
이 트리를 후위 순회(postorder) 하면서 값을 계산하면 논리식의 결과를 얻을 수 있음.
== 논리식 판별, 디지털 회로 시뮬레이션, AI 규칙 시스템 등에서 사용됨.
'이론공부 > 자료구조, 알고리즘' 카테고리의 다른 글
| 6. Graph (1) (0) | 2025.11.10 |
|---|---|
| 5. Tree (3) - Types of Binary Trees (1) | 2025.11.09 |
| 5. Tree (1) (0) | 2025.11.08 |
| 4. Linked List (3) - 복잡한 구조 표현 (0) | 2025.11.07 |
| 4. Linked List (2) - 활용 (0) | 2025.11.07 |


