1

我在数组中有以下二叉树的实现;

   32
  /  \
 2    -5
     /  \
   -331   399

数据一次分组为 3 个索引。 index%3==0是节点index%3==1的值, 是左节点index%3==2的值的索引, 是右节点的值的索引。如果左或右索引引用为 0,则该方向没有节点。

我试图找到这棵树的深度(高度)。我已经递归地写了

height(node): 
   if node == null:
        return 0
   else:
        return max(height(node.L), height(node.R)) + 1

但是,我想找到一个非递归的解决方案。

这是我的一些伪代码,假设树不为空

int i = 0; int left = 0; int right = 0;
while (i != n ){
if ( a[i+1] != 0 ){
  left++;
}
else if ( a[i+2] != 0 ){
  right++;
}
 i = i + 3;
 }

return max ( left, right ) + 1;

我认为这是不对的,我需要一些帮助来弄清楚如何正确地做到这一点。

4

1 回答 1

1

您还没有说递归的问题是什么,以便我们了解您想要改进的行为。

对此有很多解决方案,但几乎所有解决方案的性能都与您的递归解决方案相同或更差。确实,最好的解决方案将是您在创建树时必须做的事情。例如,您可以将每个节点的高度存储在每个节点的第四个数组索引中。然后每四个索引进行一次简单的扫描以找到最大高度。如果节点有与它们一起存储的父引用,那么在高度检查期间不必计算它也会变得更容易。

一种解决方案是使用堆栈模拟递归,但这实际上与递归没有什么不同。

另一种解决方案是遍历每个节点并根据其父节点确定其高度,但不是按照特定的遍历顺序。但是,由于您的配置方式,没有辅助数据结构来存储层次结构,它的效率会降低 O(n^2)。问题是如果没有完整的数组扫描,您将无法从子节点到其父节点。然后你可以在线性时间内完成(但递归也是线性时间,所以我不确定我们做得更好。从内存的角度来看,它也不会好得多)。

你能定义你想要提高什么类型的效率吗?

这是每个的伪代码,但我依赖于一些不容易出现的数据结构:

“没有递归的递归”解决方案:

int get_height(int * tree, int length) {

    Stack stack;

    int max_height = 0;

    if (length == 0) {
        return 0;
    }

    // push an "array" of the node index to process and the height of its parent.  
    //   make this a struct and use that for real c code
    stack.push(0,0);

    while(!stack.empty()) {
        int node_index, parent_height = stack.pop();

        int height = parent_height + 1;
        if (height > max_height) {
            max_height=height;
        }
        if (tree[node_index+1] != 0 )
            stack.push(tree[node_index+1], height);
        if (tree[node_index+2] != 0 )
            stack.push(tree[node_index+2], height);

    }

    return max_height;
}

现在正在研究不使用额外内存的非常慢的解决方案,但这真的很糟糕。就像递归地写斐波那契一样糟糕。原始算法遍历每个节点并执行 O(n) 检查最坏情况的 O(n^2) 运行时间(实际上并没有我最初想象的那么糟糕)

编辑:很久以后,我添加了一个优化,跳过所有有子节点的节点。这非常重要,因为它减少了很多呼叫。最好的情况是如果树实际上是一个链表,在这种情况下它在 O(n) 时间内运行。最坏的情况是一个完全平衡的树 - 每个 logn 叶节点都对 O((log(n)^2) 的根进行 logn 检查。这还不错。下面的行被标记为

“真的很慢但没有额外的内存”解决方案(但现在更新为几乎没有那么慢):

int get_height(int * tree, int length) {
    int max_height = 0;
    for (int i = 0; i < length; i+=3) {

        // Optimization I added later
        // if the node has children, it can't be the tallest node, so don't
        //   bother checking from here, as the child will be checked
        if (tree[i+1] != 0 || tree[i+2] != 0)
            continue;

        int height = 0;
        int index_pointing_at_me;

        // while we haven't gotten back to the head of the tree, keep working up
        while (index_pointing_at_me != 0) {
            height += 1; 
            for (int j = 0; j < length; j+=3) {
                if (tree[j+1] == tree[i] ||
                    tree[j+2] == tree[i]) {
                    index_pointing_at_me = j;
                    break;
                }
            }

        }
        if (height > max_height) {
            max_height = height;
        }

    }

    return max_height;
}

改进了以前的解决方案,但使用 O(n) 内存 - 这假设父母总是在数组中的孩子之前(我认为这在技术上不是必需的)

int get_height(int * tree, int length) {

    if (length == 0) 
        return 0;

    // two more nodes per node - one for which node is its parent, the other for its height
    int * reverse_mapping = malloc((sizeof(int) * length / 3) * 2) 
    reverse_mapping[1] = 1; // set height to 1 for first node



    // make a mapping from each node to the node that points TO it.
    // for example, for the first node
    //    a[0] = 32
    //    a[1] = 3
    //    a[2] = 6
    //  store that the node at 3 and 6 are both pointed to by node 0 (divide by 3 just saves space since only one value is needed) and that each child node is one taller than its parent
    int max_height = 0;
    for (int i = 0; i < length; i+=3) {

        int current_height = reverse_mapping[(i/3)*2+1];
        if (current_height > max_height)
            max_height = current_height;

        reverse_mapping[(tree[i+1]/3)*2] = i;
        reverse_mapping[(tree[i+1]/3)*2 + 1] = current_height + 1;

        reverse_mapping[(tree[i+2]/3)*2] = i;
        reverse_mapping[(tree[i+2]/3)*2 + 1] = current_height + 1;

    }
    return max_height
}
于 2013-05-19T04:46:18.613 回答