Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++로 이진 트리 레벨 순서 순회(Level Order Traversal) 한 줄씩 출력하기

이진 트리(binary tree)가 주어졌을 때, 트리의 레벨 순서 순회(level order traversal) 결과를 레벨별로 한 줄씩 출력하는 프로그램을 C++로 작성하는 방법을 알아보겠습니다.

레벨 순서 순회는 너비 우선 탐색(BFS, Breadth-First Search)이라고도 부르며, 루트가 있는 최상위 레벨부터 시작해 아래 레벨로 내려가면서 같은 레벨에 속한 노드들을 왼쪽에서 오른쪽 순서로 차례대로 방문하는 방식입니다. 일반적인 레벨 순회 출력과 달리, 이 문제에서는 각 레벨의 노드 값이 서로 다른 줄에 구분되어 나타나야 합니다.

예를 들어 다음과 같은 이진 트리가 주어졌다고 가정해 보겠습니다.

C++로 이진 트리 레벨 순서 순회(Level Order Traversal) 한 줄씩 출력하기

위 이진 트리에 대한 기대 출력은 다음과 같습니다.

Level 0: 3
Level 1: 2 1
Level 2: 10 20 30

알고리즘

각 레벨을 구분해 출력하기 위해 큐(queue) 자료구조를 활용합니다. 핵심 아이디어는 반복문이 시작될 때 큐에 들어 있는 노드의 개수를 세어 두면, 그 개수만큼만 처리했을 때 현재 레벨의 모든 노드가 출력된다는 점입니다. 한 레벨의 출력이 끝나면 줄바꿈을 해 주면 됩니다.

시작
1단계 → 노드 구조체를 정의한다.
    struct node
        struct node *left, *right
        int data
    끝
2단계 → 새 노드를 생성하는 함수를 작성한다.
    node* newnode(int data)
    node *temp = new node
    temp->data = data
    temp->left = temp->right = NULL
    return temp
3단계 → 레벨 순서 순회 함수를 작성한다.
    void levelorder(node *root)
    IF root == NULL
        Return
    End
    queue<node *> que
    que.push(root)
    Loop While que.empty() == false
        int count = que.size()   // 현재 레벨의 노드 개수
        Loop While count > 0
            node *cur = que.front()
            cur->data 출력
            que.pop()
            IF cur->left != NULL
                que.push(cur->left)
            End
            IF cur->right != NULL
                que.push(cur->right)
            End
            count를 1 감소
        End
        줄바꿈 출력   // 한 레벨이 끝났음을 의미
    End
End
4단계 → main() 함수에서
    node *root = newnode(3)으로 트리를 생성한다.
    levelorder(root)를 호출한다.
종료

C++ 예제 코드

#include <iostream>
#include <queue>
using namespace std;

// 노드 구조체 정의
struct node {
    struct node *left;
    int data;
    struct node *right;
};

// 레벨 순서 순회: 각 레벨을 한 줄씩 출력
void levelorder(node *root) {
    if (root == NULL)
        return;
    queue<node *> que;
    que.push(root);
    while (!que.empty()) {
        int count = que.size();   // 현재 레벨의 노드 개수
        while (count > 0) {
            node *cur = que.front();
            cout << cur->data << " ";
            que.pop();
            if (cur->left != NULL)
                que.push(cur->left);
            if (cur->right != NULL)
                que.push(cur->right);
            count--;
        }
        cout << endl;   // 한 레벨의 출력이 끝나면 줄바꿈
    }
}

// 새 노드를 생성하는 함수
node* newnode(int data) {
    node *temp = new node;
    temp->data = data;
    temp->left = NULL;
    temp->right = NULL;
    return temp;
}

int main() {
    // 예제 이진 트리 생성
    node *root = newnode(3);
    root->left = newnode(2);
    root->right = newnode(1);
    root->left->left = newnode(10);
    root->left->right = newnode(20);
    root->right->right = newnode(30);

    levelorder(root);
    return 0;
}

실행 결과

위 프로그램을 컴파일한 후 실행하면 다음과 같은 출력이 생성됩니다.

3 
2 1 
10 20 30 

동작 원리

코드의 동작 과정을 단계별로 살펴보면 다음과 같습니다.

  1. 루트 삽입: 먼저 루트 노드(3)를 큐에 넣습니다.
  2. 레벨 크기 확인: 큐의 크기를 count에 저장합니다. 첫 번째 반복에서 count는 1이므로 루트 하나만 출력한 뒤 줄바꿈을 합니다.
  3. 자식 노드 삽입: 노드를 출력하며 큐에서 제거할 때, 해당 노드의 왼쪽·오른쪽 자식이 존재하면 큐에 추가합니다.
  4. 반복: 다음 반복에서는 큐에 2와 1이 들어 있으므로 count는 2가 되고 "2 1"이 한 줄로 출력됩니다. 마지막으로 10, 20, 30이 "10 20 30"으로 출력됩니다.

이 방식은 트리의 모든 노드를 정확히 한 번씩 방문하므로 시간 복잡도는 O(n)이며, 최악의 경우 큐에 모든 노드가 저장될 수 있어 공간 복잡도 역시 O(n)입니다.