按顺序N创建最大树

时间:2014-12-11 14:54:18

标签: algorithm tree

A 成为 n 不同整数的数组。设 A 的最大元素的索引为 m 。将 A 上的最大树定义为 A 条目的二叉树,其中根包含 A 的最大元素, left child是 A [ 0 m-1 ]的最大树,右边的孩子是上的最大树A [ M + 1 N-1 ]。设计一个O( n )算法来构建最大树。

如果我创建一个虚拟示例,事实证明给定的数组是max-tree的INORDER遍历,对于子树根的给定条件,它们应该是最大的。

2 个答案:

答案 0 :(得分:4)

确实可以在O(n)时间内完成。我还附加了将我的解决方案与参考O(n log n)解决方案进行比较的测试用例。要解决它:

有几点意见:

  1. 提供的数组是有问题的树的inorder遍历。
  2. 树具有最大堆属性,即节点不能具有值小于其自身的祖先。
  3. 方法: 我们将从开始到结束遍历输入数组并维护包含具有递减值的节点的堆栈(从下到上)。 该堆栈将包含顶部最近构造的节点和底部具有最大值(根)的节点。

    当我们浏览阵列时:

    1. 如果stack为空,请将此节点推入堆栈。
    2. 如果stack不为空并且包含一些值小于当前值的节点,则这些值中的最大值将是当前节点的左子节点。保持弹出值,直到堆栈为空或堆栈顶部包含值>当前值。这来自观察#1和#2。
    3. 当前节点可能是堆栈顶部节点的右子节点。我们可以假设这一点,直到我们看到更大的值。
    4. 由于扫描每个节点并将其推入堆栈一次,因此它是O(n)时间解决方案。

      这是代码。 main函数创建一个包含10,000个数字的随机数组,并使用上述O(n)算法和一个朴素的O(n log n)解决方案构造max-tree。我这样做了1000次并断言这两棵树是平等的。

      #include <iostream>
      #include <algorithm>
      #include <vector>
      #include <limits>
      #include <cassert>
      #include <stack>
      #include <limits>
      
      using namespace std;
      
      struct Node {
        int data;
        Node* left, *right;
      };
      
      /******************** Solution Begin ***************************/
      Node* Construct(const vector<int>& array) {
        stack<Node*> S;
      
        for (auto&& x : array) {
          Node* node = new Node{x, nullptr, nullptr};
      
          while (!S.empty() && (S.top()->data < x)) {
            node->left = S.top();
            S.pop();
          }
      
          if (!S.empty()) {
            S.top()->right = node;
          }
          S.emplace(node);
        }
      
        Node* last_popped = nullptr;
        while (!S.empty()) {
          last_popped = S.top();
          S.pop();
        }
      
        return last_popped;
      }
      
      /******************** Solution End ***************************/
      
      Node* SlowConstructHelper(const vector<int>& array, int start, int end) {
        if (start > end) return 0;
      
        int m = start;
        for (int i = start + 1; i <= end; i++) {
          if (array[i] > array[m]) m = i;
        }
      
        Node* root = new Node;
        root->data = array[m];
        root->left = SlowConstructHelper(array, start, m - 1);
        root->right = SlowConstructHelper(array, m + 1, end);
        return root;
      }
      
      Node* SlowConstruct(const vector<int>& array) {
        return SlowConstructHelper(array, 0, array.size() - 1);
      }
      
      bool IsEqualTree(Node* tree1, Node* tree2) {
        if ((!tree1) && (!tree2)) return true;
      
        if ((!tree1) || (!tree2)) return false;
      
        return (tree1->data == tree2->data) &&
               IsEqualTree(tree1->left, tree2->left) &&
               IsEqualTree(tree1->right, tree2->right);
      }
      
      int main() {
        const int kNumRuns = 1000;
        const int kArraySize = 10000;
      
        for (int run = 0; run < kNumRuns; run++) {
          vector<int> array(kArraySize);
          for (int i = 0; i < kArraySize; i++) array[i] = i;  // Uniqueness guaranteed
      
          random_shuffle(array.begin(), array.end());
      
          Node* root1 = Construct(array);
          Node* root2 = SlowConstruct(array);
          assert(IsEqualTree(root1, root2));
        }
        return 0;
      }
      

      编辑:早期版本声称树是最大堆。将其更正为“max heap property”。

答案 1 :(得分:0)

理论上,在O(n)中看起来是不可能的,因为直到现在世界上没有可以在O(n)时间内对条目进行排序的排序算法。并且任何类型的调整逻辑都可以构建在已排序的条目上,仅用于构建树。

可以进行具有更差情况O(n2)的正常递归实现。我在编程元素访谈书中看到了同样的问题,他们没有提供任何解决方案。它也可能输入错误。

递归逻辑。

CreateTree(start, end)
if start > end return null
Find index in array between start and end inclusive which contain max value
Create Node with index value
Node.left = CreateTree(start, index - 1);
Node.right = CreateTree(index + 1, end);