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

이진 탐색 트리(BST)의 모든 노드에 더 큰 값의 합을 추가하는 방법

이 글에서는 흥미로운 트리 문제를 다뤄보겠습니다. 주어진 이진 탐색 트리(Binary Search Tree, BST)의 모든 노드에, 해당 노드보다 큰 값을 가진 모든 노드의 합을 더해 트리를 변환하는 것입니다.

변환이 완료되면 각 노드의 값은 "자기 자신을 포함하여 자신보다 크거나 같은 모든 노드 값의 누적 합"으로 바뀌게 됩니다. 변환 전과 후의 트리는 아래 그림과 같습니다.

이진 탐색 트리(BST)의 모든 노드에 더 큰 값의 합을 추가하는 방법

알고리즘

핵심 아이디어는 역중위 순회(Reverse Inorder Traversal)입니다. 일반적인 중위 순회(왼쪽 → 루트 → 오른쪽)와 반대로 오른쪽 → 루트 → 왼쪽 순서로 트리를 방문하면, 노드 값들이 내림차순으로 처리됩니다. 따라서 각 노드를 방문할 때마다 지금까지의 누적 합을 현재 노드에 더해주기만 하면 됩니다.

의사 코드는 다음과 같습니다.

bstUpdate(root, sum) −
Begin
    if root is null, then stop
    bstUpdate(right of root, sum)
    sum := sum + value of root
    update root value using sum
    bstUpdate(left of root, sum)
End

C++ 구현 예제

#include<iostream>
using namespace std;
class Node {
    public:
        int data;
        Node *left, *right;
};
Node *getNode(int item) {
    Node *newNode = new Node();
    newNode->data = item;
    newNode->left = newNode->right = NULL;
    return newNode;
}
void updateBST(Node *root, int *sum) {
    if (root == NULL)
        return;
    updateBST(root->right, sum); //오른쪽 서브트리부터 먼저 갱신
    *sum = *sum + root->data;
    root->data = *sum; //루트 노드의 값을 누적 합으로 갱신
    updateBST(root->left, sum); //마지막으로 왼쪽 서브트리 갱신
}
void BSTUpdate(Node *root) {
    int sum = 0;
    updateBST(root, &sum);
}
void inorder(Node *root) {
    if (root != NULL) {
        inorder(root->left);
        cout<<root->data<<" ";
        inorder(root->right);
    }
}
Node* insert(Node* node, int data) {
    if (node == NULL)
        return getNode(data);
    if (data <= node->data) //값이 작거나 같으면 왼쪽으로 이동
        node->left = insert(node->left, data);
    else //값이 크면 오른쪽으로 이동
        node->right = insert(node->right, data);
    return node;
}
int main() {
    int data[] = {50, 30, 20, 40, 70, 60, 80};
    int n = sizeof(data)/sizeof(data[0]);
    Node *root = NULL;
    for(int i = 0; i < n; i++) {
        root = insert(root, data[i]);
    }
    BSTUpdate(root);
    inorder(root);
}

출력 결과

350 330 300 260 210 150 80

동작 원리와 복잡도

입력 배열 {50, 30, 20, 40, 70, 60, 80}로 구성한 BST를 변환하면 각 노드의 값은 다음과 같이 계산됩니다.

  • 80 → 80
  • 70 → 70 + 80 = 150
  • 60 → 60 + 70 + 80 = 210
  • 50 → 50 + 60 + 70 + 80 = 260
  • 40 → 40 + 50 + 60 + 70 + 80 = 300
  • 30 → 30 + 40 + 50 + 60 + 70 + 80 = 330
  • 20 → 20 + 30 + 40 + 50 + 60 + 70 + 80 = 350

변환된 트리를 중위 순회하면 값이 오름차순으로 출력되므로 위와 같은 결과를 얻을 수 있습니다. 이 알고리즘은 트리의 모든 노드를 정확히 한 번씩 방문하므로 시간 복잡도는 O(n)이며, 재귀 호출에 사용되는 스택 공간 때문에 공간 복잡도는 트리의 높이 h에 비례해 O(h)입니다. 균형 잡힌 BST라면 O(log n), 최악의 경우(편향 트리)에는 O(n)이 됩니다.