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

C++에서 단 하나의 스택으로 이진 트리 리프 노드를 왼쪽에서 오른쪽으로 출력하는 방법


이번 글에서 다룰 문제는 이진 트리의 리프 노드를 왼쪽에서 오른쪽 순서대로 출력하는 것입니다. 여기서 핵심 과제는 오직 하나의 스택만 사용해야 한다는 제약 조건입니다.

push() 함수를 통해 이진 트리의 노드들을 스택에 삽입하고, pop() 연산을 통해 리프 노드를 화면에 출력합니다.

리프 노드란 왼쪽과 오른쪽 포인터가 모두 NULL인 말단 노드를 의미합니다. 즉, 해당 노드는 자식 노드를 가지지 않는, 부모 노드가 아닌 노드입니다.

예시

입력 : 12 21 32 41 59 33 70
출력 : 41 59 33 70

C++에서 단 하나의 스택으로 이진 트리 리프 노드를 왼쪽에서 오른쪽으로 출력하는 방법

스택(stack)은 LIFO(Last In, First Out, 후입선출) 방식으로 동작하는 자료구조로, top 포인터는 가장 마지막에 삽입된 요소를 가리킵니다. 이러한 구조적 특성 때문에 스택에 나중에 들어간 노드일수록 다른 노드보다 먼저 꺼내지게 되며, 이 원리를 활용하면 추가 자료구조 없이 리프 노드를 순서대로 출력할 수 있습니다.

아래 코드는 설명한 알고리즘을 C++ STL을 사용해 구현한 예제입니다.

알고리즘

시작
    1단계 -> 구조체 타입의 노드 변수 생성
        int형 data 선언
        node 타입의 포인터 *left, *right 선언
    2단계 -> val을 매개변수로 받는 노드 생성 함수 작성
        new(malloc)으로 node 변수 할당
        node->data = val 설정
        node->left = node->right = NULL 설정
        node 반환
    3단계 -> void leaf(Node *ptr) 함수 선언
        stack<Node*> stck 생성
        While 1 (무한 반복)
        IF ptr이 NULL이 아니면
            stck.push(ptr)
            ptr = ptr->left
        ELSE
            IF 스택이 비어 있으면(stck.empty())
                Break
            ELSE
                IF stck.top()->right == NULL이면
                    ptr = stck.top()
                    stck.pop()
                    IF ptr->left == NULL이면
                        ptr->data 출력   // 리프 노드
                    END
                END
                WHILE ptr == stck.top()->right인 동안 반복
                    ptr = stck.top()
                    stck.pop()
                    IF 스택이 비어 있으면
                        Break
                    END
                END
                IF !stck.empty()이면
                    ptr = stck.top()->right
                ELSE
                    ptr = NULL
                ENDIF
            END
        END
    4단계 -> main() 함수에서
        삽입할 값을 인자로 New 호출 (예: Node* root = New(12))
        leaf(root) 호출
종료

C++ 구현 코드

#include <bits/stdc++.h>
using namespace std;
// 노드 구조체 정의
struct Node {
    Node* left;
    Node* right;
    int data;
};
// 새 노드를 생성하는 함수
Node* New(int val) {
    Node* node = new Node();
    node->left = node->right = NULL;
    node->data = val;
    return node;
}
// 스택을 이용해 리프 노드 출력
void leaf(Node* ptr) {
    // 노드를 저장할 스택
    stack<Node*> stck;
    while (1) {
        if (ptr) {
            stck.push(ptr);
            ptr = ptr->left;
        } else {
            if (stck.empty())
                break;
            else {
                if (stck.top()->right == NULL) {
                    ptr = stck.top();
                    stck.pop();
                    // 리프 노드 출력
                    if (ptr->left == NULL)
                        printf("%d ", ptr->data);
                }
                while (ptr == stck.top()->right) {
                    ptr = stck.top();
                    stck.pop();
                    if (stck.empty())
                        break;
                }
                if (!stck.empty())
                    ptr = stck.top()->right;
                else
                    ptr = NULL;
            }
        }
    }
}
int main() {
    printf("leaf nodes at end level are : ");
    Node* root = New(12);
    root->left = New(21);
    root->right = New(32);
    root->left->left = New(41);
    root->left->right = New(59);
    root->right->left = New(33);
    root->right->right = New(70);
    leaf(root);
    return 0;
}

출력 결과

위 프로그램을 실행하면 다음과 같은 결과가 출력됩니다.

leaf nodes at end level are : 41 59 33 70

작동 원리 요약

이 알고리즘은 반복문 기반의 중위 순회(inorder traversal)와 유사한 방식으로 동작합니다.

  1. 현재 노드가 존재하면 스택에 push하고 왼쪽 자식으로 이동합니다.
  2. 현재 노드가 NULL이 되면 스택의 top을 살펴봅니다.
  3. top 노드의 오른쪽 자식이 없다면 해당 노드를 pop하고, 왼쪽 자식까지 없다면 리프 노드이므로 값을 출력합니다.
  4. 방금 꺼낸 노드가 부모 노드의 오른쪽 자식이라면 오른쪽 서브트리 처리가 끝난 것이므로 부모 노드도 연속해서 pop합니다.
  5. 스택이 비어 있지 않다면 top 노드의 오른쪽 자식으로 이동해 같은 과정을 반복하고, 스택이 비면 종료합니다.