如何用单个子节点删除树节点的子节点

时间:2016-02-02 10:17:53

标签: algorithm tree tree-traversal preorder

我有一个用于树的预先遍历遍历的数组(节点值是深度值)。我想做的就是通过删除只有一个孩子的内部节点的子节点来最小化树。

作为示例(最大深度= 3的树) problem visualized here

输入数组:[0,1,2,3,3,1,2,3]
输出数组:[0,1,2,2,1]

算法怎么样?

2 个答案:

答案 0 :(得分:1)

简单的O(nlog(n))平均案例算法来自于通过分而治之的方法攻击问题。

input_level = 0output_level=0left=0right=n-1开始。

在每个递归步骤中,计算范围为[input_level+1A]的输入数组left中值为right的元素。这些是当前节点的子节点。如果没有这样的元素,请打印output_level并返回。如果只有一个这样的元素,“删除”当前节点(即不打印它),将left增加1,并递归调用该函数。如果有两个或更多这样的元素,打印output_level,将output_level增加1,并递归地将函数应用于子元素划分的每个区间。执行递归调用时始终增加input_level

对于示例输入A=[0, 1, 2, 3, 3, 1, 2, 3],首先算法将在索引1和5处找到值为1的元素。然后它将打印0,将output_levelcurrent_level增加1,并递归调用两次:在[1,4]和[5,7]范围内。

在最坏的情况下(对于实际上是列表的简并树),O(n 2 )的复杂性是平均的O(nlog(n)),随机的n-ary树的高度为O(log(n))。

答案 1 :(得分:0)

以下算法在O(N)中运行。我想这次我说得对。

#include <algorithm>
#include <iostream>
#include <stack>
#include <tuple>
#include <utility>
#include <vector>

void mark_nodes(const std::vector<unsigned>& tree,
                std::vector<bool>& mark) {
  // {depth, index, mark?}
  using triple = std::tuple<unsigned, unsigned, bool>;
  std::stack<triple> stk;
  stk.push({0, 0, false});
  for (auto i = 1u; i < mark.size(); ++i) {
    auto depth = tree[i];
    auto top_depth = std::get<0>(stk.top());
    if (depth == top_depth) {
      stk.pop();
      if (stk.size()) std::get<2>(stk.top()) = false;
      continue;
    }
    if (depth > top_depth) {
      std::get<2>(stk.top()) = true;
      stk.push({depth, i, false});
      continue;
    }
    while (std::get<0>(stk.top()) != depth) {
      mark[std::get<1>(stk.top())] = std::get<2>(stk.top());
      stk.pop();
    }
    mark[std::get<1>(stk.top())] = std::get<2>(stk.top());
    stk.pop();
    if (stk.size()) std::get<2>(stk.top()) = false;
    stk.push({depth, i, false});
  }
  mark[0] = false;
}

std::vector<unsigned> trim_single_child_nodes(
    std::vector<unsigned> tree) {
  tree.push_back(0u);
  std::vector<bool> mark(tree.size(), false);
  mark_nodes(tree, mark);
  std::vector<unsigned> ret(1, 0);
  tree.pop_back();
  mark.pop_back();
  auto max_depth = *std::max_element(tree.begin(), tree.end());
  std::vector<unsigned> depth_map(max_depth + 1, 0);
  for (auto i = 1u; i < tree.size(); ++i) {
    if (mark[i]) {
      if (tree[i] > tree[i - 1]) {
        depth_map[tree[i]] = depth_map[tree[i - 1]];
      }
    } else {
      if (tree[i] > tree[i - 1]) {
        depth_map[tree[i]] = depth_map[tree[i - 1]] + 1;
      }
      ret.push_back(depth_map[tree[i]]);
    }
  }
  return ret;
}

int main() {
  std::vector<unsigned> input = {0, 1, 2, 3, 3, 1, 2, 3};
  auto output = trim_single_child_nodes(input);
  for (auto depth : output) {
    std::cout << depth << ' ';
  }
}