1. 이진 트리 순회 (Binary Tree Traversal)
이진 트리는 비선형 자료구조이기 때문에 순차적으로 방문할 수 없다. 탐색 방법에 따라 노드를 방문하는 순서가 달라지는데, 이진 트리 순회 방법은 전위(Preorder), 중위(Inorder), 후위(Postorder) 순회 세 가지로 분류된다. 루트 노드의 자식 노드는 서브 트리의 루트 노드로 볼 수 있다. 이런 재귀적 특성을 갖는 구조 때문에 재귀적 방법의 순회는 매우 쉽게 구현할 수 있다. 재귀적 방법이 아닌 반복문을 사용하는 반복적(Iterative) 순회도 가능하다. 트리 순회를 공부하면서 재귀적 순회를 구현 완료 후 반복적 순회 구현을 시도했는데, 간단할 줄 알았지만 생각 이상으로 정말 어려웠다(후위 순회 구현은 실패). 방법을 알고난 지금은 단순하다고 느끼지만 모르면 떠올리기 쉽지 않은 내용인 것 같아 이 글에 정리한다.
2. 전위 순회 (Preorder Traversal)
전위 순회의 탐색 순서는 루트 노드를 먼저 방문 후 서브 트리를 탐색하는 것이다. 코드에선 왼쪽 서브트리 탐색 후 오른쪽 서브트리를 탐색한다.
void IterPreorder()
{
if (!root_) return;
Stack<Node*> s;
s.Push(root_);
// 스택에 방문할 노드가 있으면 반복
while (!s.IsEmpty())
{
// 스택에서 노드를 꺼낸다
Node* cur = s.Top();
s.Pop();
// 루트 노드를 방문
Visit(cur);
// 오른쪽 자식노드 있으면 스택에 넣는다
if (cur->right)
{
s.Push(cur->right);
}
// 왼쪽 자식노드 있으면 스택에 넣는다
if (cur->left)
{
s.Push(cur->left);
}
}
}
C++
복사
3. 중위 순회 (Inorder Traversal)
탐색 순서는 왼쪽 서브트리 → 루트 노드 → 오른쪽 서브트리이다.
void IterInorder()
{
if (!root_) return;
Stack<Node*> s;
Node* cur = root_;
// cur이 nullptr고 스택이 비면 반복 종료
while (cur || !s.IsEmpty())
{
// cur이 nullptr가 아니면 스택에 cur 노드를 넣고
// 왼쪽 자식 노드로 내려간다
while (cur)
{
s.Push(cur);
cur = cur->left;
}
// cur이 nullptr면 스택에서 노드를 꺼낸 후 그 노드로 이동
cur = s.Top();
s.Pop();
// cur의 왼쪽 서브트리는 탐색이 끝났으므로 cur을 방문
Visit(cur);
// cur의 오른쪽 서브트리 탐색을 위해 오른쪽 자식 노드로 이동
cur = cur->right;
}
}
C++
복사
4. 후위 순회 (Postorder Traversal)
순회 순서는 왼쪽 서브트리 → 오른쪽 서브트리 → 루트 노드이다. 스택을 두 개 사용한다. 이런 식으로 해결하는 것은 처음에 떠올리지 못 했다. 단순하지만 기발한 방법인 것 같다. 첫 번째 반복에선 방문하지 않고 s2 스택에 모든 노드를 넣는다. 두 번째 반복에선 s2에서 노드를 꺼내면서 방문한다. s1의 역할은 s2에 노드가 올바른 순서로 들어가도록 하는 것이다.
void IterPostorder()
{
if (!root_) return;
Stack<Node*> s1, s2;
s1.Push(root_);
// s1에 노드가 있으면 반복
while (!s1.IsEmpty())
{
// s1에 있는 노드를 꺼내서 s2에 넣는다
s2.Push(s1.Top());
s1.Pop();
// s2에 방금 넣은 노드가 cur
Node* cur = s2.Top();
// cur의 왼쪽 자식 노드가 있으면 s1에 넣는다
if (cur->left)
{
s1.Push(cur->left);
}
// cur의 오른쪽 자식 노드가 있으면 s1에 넣는다
if (cur->right)
{
s1.Push(cur->right);
}
}
// s2에 노드가 있으면 노드를 꺼내서 방문
while (!s2.IsEmpty())
{
Visit(s2.Top());
s2.Pop();
}
}
C++
복사