在没有递归的情况下迭代O(1)空间中的AVL树

时间:2011-12-15 10:38:43

标签: c algorithm data-structures

我有一个AVL树。每个节点如下所示:

typedef struct {
    Node *parent;  // the parent node
    Node *left;    // the node left of this node
    Node *right;   // the node right of this node
    int height;    // the height of this node
    void *value;   // payload
} Node;

是否可以在O(1)空间中使用这些节点迭代AVL树,不带递归,如果是,如何?

如果没有,那么也可以使用具有亚O(n)空间或iff真正必要的O(N)空间的解决方案。

迭代树我的意思是我想要访问每个节点一次,如果可能的话,按顺序(从最左边到mostright节点)。

3 个答案:

答案 0 :(得分:6)

如果存储了您访问过的最后一个节点,则可以在迭代器中派生要访问的下一个节点。

  • 如果最后一个节点是您的父节点,请按下左侧子树。
  • 如果最后一个节点是您的左子树,请按下右侧子树。
  • 如果最后一个节点是您正确的子树,请转到您的父节点。

该算法为您提供了树的O(1)遍历。你需要对叶子进行一些充实,然后决定你想要决定迭代器应该在哪里进行迭代器(pre / in / post-order),并等待增量。

答案 1 :(得分:0)

只要保留父指针,就可以在给定指向某个节点的指针的情况下获取下一个有序节点。这可以用于从最左边的节点开始迭代树。来自my implementation of AVL tree

BAVLNode * BAVL_GetNext (const BAVL *o, BAVLNode *n)
{
    if (n->link[1]) {
        n = n->link[1];
        while (n->link[0]) {
            n = n->link[0];
        }
    } else {
        while (n->parent && n == n->parent->link[1]) {
            n = n->parent;
        }
        n = n->parent;
    }

    return n;
}

获取最左边的节点:

BAVLNode * BAVL_GetFirst (const BAVL *o)
{
    if (!o->root) {
        return NULL;
    }

    BAVLNode *n = o->root;
    while (n->link[0]) {
        n = n->link[0];
    }

    return n;
}

此处,node->link[0]node->link[1]分别是节点的左右子节点,node->parent是指向父节点的指针(或NULL表示根节点)。

单个GetNext()操作具有O(logn)时间复杂度。但是,当用于迭代整个树时,您将获得O(n)摊销的时间复杂度。

答案 2 :(得分:0)

Harry Lewis和Larry Denenberg的“数据结构及其算法”描述了对二叉树的恒定空间遍历的链接反转遍历。为此,您不需要在每个节点上使用父指针。遍历使用树中的现有指针来存储用于反向跟踪的路径。需要2-3个额外的节点引用。加上每个节点上的一点,以便在我们向下移动时跟踪遍历方向(向上或向下)。在我从书中实现这些算法时,分析表明这种遍历具有更少的内存/处理器时间。 java中的实现(我猜的c会更快)是here