【问题标题】:Why a self-referencing sentinel in a red-black tree is simpler than having to check for NULL?为什么红黑树中的自引用哨兵比检查 NULL 更简单?
【发布时间】:2017-07-19 11:52:55
【问题描述】:

我正在尝试实现红黑树数据结构,并遇到了来自 Apple 开源项目的 this 示例。这是创建树的代码:

/*
 * Create a red black tree struct using the specified compare routine.
 * Allocates and returns the initialized (empty) tree.
 */
struct rbtree *
rbcreate(compar)
    int (*compar)__P((const void *, const void*));
{
    struct rbtree *tree;

    tree = (struct rbtree *) emalloc(sizeof(*tree));
    tree->compar = compar;

    /*
     * We use a self-referencing sentinel node called nil to simplify the
     * code by avoiding the need to check for NULL pointers.
     */
    tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil;
    tree->nil.color = black;
    tree->nil.data = NULL;

    /*
     * Similarly, the fake root node keeps us from having to worry
     * about splitting the root.
     */
    tree->root.left = tree->root.right = tree->root.parent = &tree->nil;
    tree->root.color = black;
    tree->root.data = NULL;

    return(tree);
}

我想知道让哨兵节点而不是让子节点指向NULL 的原因是什么。无论如何,据我所知,我们必须进行检查。

我也不明白为什么我们需要假根,以及根在理论上是如何分裂的?

【问题讨论】:

  • 如果我没记错的话,一个常见的技巧是将“r-b-flag”放入其中一个通常为 0 的子指针的最低位(由于地址的字对齐)。这为每个节点节省了一个字节甚至一个字。在这种情况下,与 0 的比较可能必须掩盖这一点 - 与自身的比较不是。但是,这只是猜测......
  • @Scheff:可能是这样,但这里引用的代码似乎存储了一个单独的颜色成员。
  • 对不起,我什至没有阅读代码 - 我的错......

标签: c data-structures tree binary-search-tree


【解决方案1】:

假设您要检查 RB 树的主要属性之一,即没有相邻的红色节点。

使用 NULL 表示,它看起来像这样:

node->color == black || (node->left == NULL || node->left->color == black) && (node->right == NULL || node->right->color == black)

哨兵表示可以更简洁地表达它:

node->color == black || node->left->color == black && node->right->color == black

同样的简化适用于树操作中的实际检查。

与假根类似的故事。它确保树永远不会为空,从而消除了树插入例程中的特殊情况。 (不过不知道他们吐口水是什么意思。)

【讨论】:

  • 除了使用哨兵而不是 NULL 减少链接数据结构中的特殊情况外,还允许代码推测性地遵循链,为优化器提供更多重新排序的余地。
猜你喜欢
  • 2014-09-23
  • 2018-06-17
  • 2020-12-02
  • 2015-05-18
  • 2011-08-29
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
  • 2015-12-31
相关资源
最近更新 更多