简体   繁体   English

数组遍历中的BST

[英]BST in array traversal

I have the following implementation of a binary tree in an array; 我在数组中有以下二叉树的实现;

   32
  /  \
 2    -5
     /  \
   -331   399

The data is grouped 3 indexes at a time. 数据一次被分组为3个索引。 index%3==0 is the value of the node, index%3==1 is the index of the value of the left node and index%3==2 is the index of the value of the right node. index%3==0是节点的值, index%3==1是左节点的值的index%3==2index%3==2是右节点的值的索引。 If the left or right index reference is 0, there is no node that direction. 如果左或右索引参考为0,则没有该方向的节点。

I'm trying to find the depth (height) of this tree. 我试图找到这棵树的深度(高度)。 I've written it recursively 我已经递归地写了

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

I want to find a non-recursive solution, however. 我想找到一个非递归的解决方案。

Here is some pseudocode i have, assuming the tree is not empty 这是我拥有的一些伪代码,假设树不为空

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;

I don't think this is right and I'd like some help figuring out how to do this correctly. 我认为这是不对的,我希望获得一些帮助来弄清楚如何正确执行此操作。

You haven't said what your problem is with recursion for us to understand what behavior you want to improve. 您没有说过递归问题是什么,以便我们了解您想要改善的行为。

There are many solutions to this, but almost all of them have the same or worse performance than your recursive solution. 有很多解决方案,但是几乎所有这些解决方案都具有与递归解决方案相同或更差的性能。 Really, the best solutions are going to be things you'd have to do when you're creating the tree. 确实,最好的解决方案将是在创建树时必须要做的事情。 For example, you could store the height of each node in a fourth array index per node. 例如,您可以将每个节点的高度存储在每个节点的第四个数组索引中。 Then it's a trivial scan of every fourth index to find the max height. 然后,对每个第四个索引进行琐碎的扫描以找到最大高度。 It would also make it easier if nodes had parent references stored with them so that didn't have to be computed during the height check. 如果节点上存储有父级引用,这也将变得更加容易,这样就不必在高度检查期间进行计算。

One solution is to simulate recursion with a stack, but that's really no different than recursion. 一种解决方案是使用堆栈模拟递归,但这实际上与递归没有什么不同。

Another solution is to go through each node and determine its height based on it's parent, but not in a specific traversal's order. 另一种解决方案是遍历每个节点并根据其父节点确定其高度,但不按特定遍历的顺序进行。 However, because of how you have this configured, without a secondary datastructure to store the hierarchy, it's going to be less efficient O(n^2). 但是,由于配置方式的原因,而没有用于存储层次结构的辅助数据结构,效率会降低O(n ^ 2)。 The problem is you can't get from the child to its parent without a full array scan. 问题是,如果没有完整的阵列扫描,您将无法从孩子那里得到父母。 Then you can do it in linear time (but recursion is also linear time, so I'm not sure we're doing better. It's also not going to be much better from a memory perspective). 然后,您可以在线性时间内做到这一点(但是递归也是线性时间,因此我不确定我们做得更好。从内存的角度来看,也不会变得更好)。

Can you define what type of efficiency you want to improve? 您可以定义要提高哪种效率?

Here's the pseudocode for each, but I'm depending on a few datastructures that aren't easily present: 这是每个的伪代码 ,但是我依赖于一些不容易呈现的数据结构:

"recursion without recursion" solution: “递归不递归”解决方案:

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;
}

Now working on really slow solution that uses no additional memory, but it's REALLY bad. 现在正在研究一种非常慢的解决方案,该解决方案不使用任何额外的内存,但这确实很糟糕。 It's like writing fibonacci recursively bad. 就像递归地写斐波那契一样。 The original algorithm went through each node and performed O(n) checks worst case for a runtime of O(n^2) (actually not quite as bad as I had originally thought) 原始算法遍历每个节点并执行O(n)检查最坏情况,以获取O(n ^ 2)的运行时间(实际上并没有我最初想象的那么糟糕)

edit: much later I'm adding an optimization that skips all nodes with children. 编辑:很久以后,我要添加一个优化,以跳过所有带有孩子的节点。 This is REALLY important, as it cuts out a lot of calls. 这非常重要,因为它可以减少大量呼叫。 Best case is if the tree is actually a linked list, in which case it runs in O(n) time. 最好的情况是,树实际上是一个链表,在这种情况下,树的运行时间为O(n)。 Worst case is a fully balanced tree - with logn leaf nodes each doing logn checks back to the root for O((log(n)^2). Which isn't nearly so bad. Lines below to be marked as such 最坏的情况是一棵完全平衡的树-每个登录树的叶子节点都进行登录,然后检查回O((log(n)^ 2)的根。这还不算太糟。下面的几行标记为

"really slow but no extra memory" solution (but now updated to not be nearly so slow): “确实很慢,但没有额外的内存”解决方案(但现在更新为不会太慢):

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;
}

Improved on previous solution, but uses O(n) memory - this assumes parents are always before children in array (which I suppose isn't technically required) 在以前的解决方案上进行了改进,但是使用了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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM