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

C++로 전위 순회 문자열에서 이진 트리 복구하기

이진 트리가 하나 있다고 가정해 보겠습니다. 우리는 루트 노드에서 시작하여 전위(preorder) 깊이 우선 탐색(DFS)을 수행합니다.

탐색 과정에서 각 노드를 방문할 때마다 해당 노드의 깊이(D)만큼 대시(-)를 출력한 뒤, 그 다음에 노드의 값을 출력합니다. 노드의 깊이가 D라면 그 직계 자식의 깊이는 D+1이 되고, 루트 노드의 깊이는 0입니다.

또 한 가지 중요한 조건이 있습니다. 어떤 노드에 자식이 하나만 있다면, 그 자식은 반드시 왼쪽 자식이라는 점입니다. 따라서 위 규칙에 따라 생성된 탐색 결과 문자열 S가 주어졌을 때, 원래의 트리를 복원하고 그 루트 노드를 반환해야 합니다.

예를 들어 입력이 "1-2--3--4-5--6--7"과 같다면, 복구된 트리는 다음과 같습니다.

C++로 전위 순회 문자열에서 이진 트리 복구하기

해결 방법

이 문제는 스택(stack)을 활용하면 효율적으로 해결할 수 있습니다. 핵심 아이디어는 대시(-)의 개수로 각 노드의 깊이를 파악하고, 스택의 크기를 현재 깊이에 맞게 조정하면서 부모-자식 관계를 연결하는 것입니다. 알고리즘 단계는 다음과 같습니다.

  • 스택 st를 하나 정의합니다.

  • i := 0, n := 문자열 S의 길이로 초기화합니다.

  • lvl := 0, num := 0으로 초기화합니다.

  • i < n인 동안 다음을 반복합니다.

    • S[i]가 '-'인 동안 lvl을 1씩 증가시키고 i를 1씩 증가시켜 현재 노드의 깊이를 구합니다.

    • num := 0으로 초기화합니다.

    • i < n이고 S[i]가 '-'가 아닌 동안 num = num * 10 + (S[i] - '0')을 수행하여 연속된 숫자를 하나의 값으로 만들고 i를 증가시킵니다.

    • 스택의 크기가 lvl보다 큰 동안 스택에서 요소를 제거(pop)합니다. 이렇게 하면 스택에는 현재 노드의 조상들만 남게 됩니다.

    • num 값을 가지는 새로운 트리 노드 temp를 생성합니다.

    • 스택이 비어 있지 않고 스택 최상단 노드의 왼쪽 자식이 NULL이라면, 그 왼쪽 자식을 temp로 설정합니다.

    • 그렇지 않고 스택이 비어 있지 않다면, 스택 최상단 노드의 오른쪽 자식을 temp로 설정합니다.

    • temp를 스택에 삽입(push)합니다.

  • 모든 문자를 처리한 후, 스택의 크기가 1보다 큰 동안 요소를 제거합니다.

  • 스택이 비어 있으면 NULL을, 그렇지 않으면 스택의 최상단 요소(루트 노드)를 반환합니다.

아래 구현 예제를 통해 더 잘 이해해 보겠습니다.

예제 코드

#include <bits/stdc++.h>
using namespace std;
class TreeNode{
   public:
   int val;
   TreeNode *left, *right;
   TreeNode(int data){
      val = data;
      left = NULL;
      right = NULL;
   }
};
void inord(TreeNode *root){
   if(root != NULL){
      inord(root->left);
      cout << root->val << " ";
      inord(root->right);
   }
}
class Solution {
   public:
   TreeNode* recoverFromPreorder(string S) {
      stack<TreeNode*> st;
      int i = 0;
      int n = S.size();
      int lvl = 0;
      int num = 0;
      while (i < n) {
         for (lvl = 0; S[i] == '-'; lvl++, i++)
         ;
         num = 0;
         while (i < n && S[i] != '-') {
            num = num * 10 + (S[i] - '0');
            i++;
         }
         while (st.size() > lvl)
         st.pop();
         TreeNode* temp = new TreeNode(num);
         if (!st.empty() && !st.top()->left) {
            st.top()->left = temp;
         }
         else if (!st.empty()) {
            st.top()->right = temp;
         }
         st.push(temp);
      }
      while (st.size() > 1)
      st.pop();
      return st.empty() ? NULL : st.top();
   }
};
main(){
   Solution ob;
   TreeNode *root = ob.recoverFromPreorder("1-2--3--4-5--6--7");
   inord(root);
}

입력

"1-2--3--4-5--6--7"

출력

3 2 4 1 6 5 7