지난 시간에는 대부분의 비선형구조인 트리, 그래프, 힙에 많이 사용되는 재귀를 학습했는데 이번 시간에는 비선형구조 중 하나인 트리를 배워보겠습니다.
🔎먼저 트리의 정의와 용어를 알아보겠습니다.
🔖트리: 서로 연결된 Node의 계층형 자료구조로서, root와 부모-자식 관계의 subtree로 구성되어 있는 구조를 말한다.
💡선형 자료구조란 하나의 자료 뒤에 하나의 자료가 존재하는 것을 말하며, 비선형 자료구조는 하나의 자료 뒤에 여러 개의 자료가 존재하는 것을 말합니다.
트리를 만드는 방법은 간단하다. Node 클래스를 이용해서 left와 right에 새 노드를 가리키게만 해주면 된다.
public class Main {
public static void main(String[] args) {
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.right = new Node(6);
}
public static class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
this.left = null;
this.right = null;
}
}
}
선형 자료구조인 배열과 링크드 리스트의 경우, for문 안에서 인덱스를 기반으로 탐색을 쉽게 할 수 있기 때문에 순회 방법을 따로 배우지 않았습니다.
그러나, 트리는 비선형 자료구조이기 때문에 level order traversal, preorder traversal, inorder traversal, 그리고 postorder traversal과 같이 여러가지 방법이 있습니다.
이번 시간에는 그래프의 bfs(breadth-first-search)와 비슷한 level order traversal을 배워보겠습니다.

위와 같이 root로부터 시작되는 트리가 있다고 가정하겠습니다. 앞선 용어 정리에서 level은 "root 노드로부터 떨어진 거리"라고 했는데요, level order traversal은 level 별로 노드를 방문하는 방법을 말하기 때문에 노드 방문 순서는 다음과 같습니다:
level 0: A
level 1: B -> C -> D
level 2: E -> F -> G -> H -> I
level 3: J -> K -> L
강사님께서는 levelorder 코드 템플릿을 그냥 손이 자동으로 칠 정도로 암기하라고 하셨지만, 저는 맹목적인 암기는 지양하는 편이기 때문에 순서대로 알고리즘을 작성해보겠습니다.
📢노드의 방문과 접근을 다르게 보기 위해 방문은 visited라는 배열을, 노드에 접근해서 인접 노드가 있는지 확인하기 위한 자료구조는 FIFO(First-In-First-Out)의 Deque를 사용합니다.
package src.recursion.tree;
import java.util.*;
class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
this.left = null;
this.right = null;
}
}
public class LevelOrderTraversal {
public List<Integer> levelOrder(Node root) {
// base condition
if (root == null) {
return new ArrayList<>(); // null 대신 빈 리스트를 반환해야 안전
}
// 사전 세팅
List<Integer> visited = new ArrayList<>();
Queue<Node> q = new LinkedList<>();
// Enqueue Root
q.offer(root);
// 인접 노드 탐색
while (!q.isEmpty()) {
// Dequeue a front node in the queue
Node curNode = q.poll();
visited.add(curNode.value);
if (curNode.left != null) {
q.offer(curNode.left);
}
if (curNode.right != null) {
q.offer(curNode.right);
}
}
return visited;
}
}
add()는 큐에 요소를 추가할 때, 큐가 꽉 차면 IllegalStateException 예외를 발생offer()는 큐가 꽉 차면 false를 반환remove()는 큐가 비어 있을 때 NoSuchElementException 예외를 발생poll()은 큐가 비어 있으면 null을 반환🔖polling: 네트워크나 컴퓨터 과학에서는 상태를 주기적으로 감시하거나 확인하는 행위를 의미하는데, 큐에서는 큐의 상태(맨 앞 요소)를 확인하고 꺼내는 동작을 말한다.