【问题标题】:Red-Black Tree Deleting Problem C#红黑树删除问题 C#
【发布时间】:2011-01-19 20:09:21
【问题描述】:

我正在尝试在 C# 中实现红黑树。我已经创建了一个名为 sRbTreeNode 的对象,它具有字符串键、颜色、左、右和父属性。 我成功地实现了方法 Insert、InsertFixUp、LeftRotate、RightRotate、Delete,现在我在使用 DeleteFixUp 方法时遇到了问题。

DeleteFixUp 负责在删除后再次平衡树(使用旋转和更改节点颜色)。

我尝试从一本名为“算法简介”的书中找到的伪代码实现该方法。

这是我的代码:

private static void DeleteFixup(ref sRbTreeNode root, sRbTreeNode x)
    {
        sRbTreeNode y;

        while (x != root && x.Color == BLACK)
        {
            if (x == x.Parent.Left)         // determine sub tree from parent
            {
                y = x.Parent.Right;         // y is x's sibling 
                if (y.Color == RED)
                {   // x is black, y is red - make both black and rotate
                    y.Color = BLACK;
                    x.Parent.Color = RED;
                    LeftRotate(ref root, x.Parent);
                    y = x.Parent.Right;
                }
                if (y.Left.Color == BLACK &&
                    y.Right.Color == BLACK)
                {   // children are both black
                    y.Color = RED;      // change parent to red
                    x = x.Parent;                   // move up the tree
                }
                else
                {
                    if (y.Right.Color == BLACK)
                    {
                        y.Left.Color = BLACK;
                        y.Color = RED;
                        RightRotate(ref root, y);
                        y = x.Parent.Right;
                    }
                    y.Color = x.Parent.Color;
                    x.Parent.Color = BLACK;
                    y.Right.Color = BLACK;
                    LeftRotate(ref root, x.Parent);
                    x = root;
                }
            }
            else
            {   // right subtree - same as code above with right and left swapped
                y = x.Parent.Left;
                if (y.Color == RED)
                {
                    y.Color = BLACK;
                    x.Parent.Color = RED;
                    RightRotate(ref root, x.Parent);
                    y = x.Parent.Left;
                }
                if (y.Right.Color == BLACK &&
                    y.Left.Color == BLACK)
                {
                    y.Color = RED;
                    x = x.Parent;
                }
                else
                {
                    if (y.Left.Color == BLACK)
                    {
                        y.Right.Color = BLACK;
                        y.Color = RED;
                        LeftRotate(ref root, y);
                        y = x.Parent.Left;
                    }
                    y.Color = x.Parent.Color;
                    x.Parent.Color = BLACK;
                    y.Left.Color = BLACK;
                    RightRotate(ref root, x.Parent);
                    x = root;
                }
            }
        }

        x.Color = BLACK;
    }

我每次在不同的地方都会遇到错误“对象引用未设置为对象的实例”...

我在互联网上搜索了这个的实现,刚刚找到了一篇关于 CodeProject 的文章,它的实现和我完全一样。我尝试复制他们的代码,希望我的眼睛错过了什么,但它也没有工作......

在我开始扯头发之前,谁能帮帮我!!... ?? :)

【问题讨论】:

  • 您听说过 TDD 吗?还是单元测试?
  • 当然,我通常会在开始编码之前编写一些测试。这一次我认为它会非常简单,因为我有伪代码,我只需要翻译它。一旦我看到它不起作用,我就开始为它编写一些测试,但我仍然无法理解它有什么问题......
  • 伪代码往往没有任何错误处理...

标签: c# algorithm binary-tree red-black-tree


【解决方案1】:

虽然可能无法直接回答您的问题,但您只需在调试器中单步执行代码即可了解令人难以置信的数量。 另外您可能会自己解决问题!如果您需要帮助设置断点、检查变量或步进,请告诉我。 Visual Studio 使用起来非常简单,几乎是脑残。

【讨论】:

  • 我对 vs 调试器非常熟悉,因为我已经多次使用它来解决我的编码问题。这一次,我只是无法理解和跟踪引擎盖下发生的事情,即使我写了它! :)
  • @gillyb:不是你写的,是你从非工作版本移植过来的。
【解决方案2】:

经过一番研究,我发现问题出在我处理我构建的红黑树的方式上。

根据有关该主题的书籍(包括我正在学习的书籍!),您应该让树​​底部的每个节点都指向一个“空节点”。空节点是没有值且颜色为黑色的节点。我以为我不必在我的树上实现空节点,并且在每个检查黑色节点的地方,我添加了“|| node == null”,因为它可能正在检查空节点。 问题是有时您需要检查空节点的父节点,如果您实际上没有实现“空节点”,那么在尝试访问它的 Parent 属性时会出错。

我通过向每个没有子节点的节点添加一个具有空值和黑色的节点来实现一个“空节点”。它需要对树上的大多数操作方法进行一些调整,但最终它解决了(几乎)我所有的问题。

感谢大家帮助我! :)

【讨论】:

    【解决方案3】:

    有空参数滑入某处。

    如果是x == null,那么我们一测试if就会崩溃。

    如果x.Parent 的任何孩子为空,我们也会崩溃。

    您需要测试这些 null 条件并适当地处理它们。

    【讨论】:

      【解决方案4】:

      让我们看看...

         while (x != root && (x == null || x.Color == BLACK))
          {
              if (x == x.Parent.Left)         // determine sub tree from parent
      

      因此,如果 x 在开始时为 null,则尝试取消对 x.Parent 的引用,这将引发您遇到的异常。我看了两行,已经发现了一个错误。

      您需要在取消引用之前的某个时间检查每个引用是否为空。

      【讨论】:

      • 对于这个错误,我很抱歉,但我已经尝试过了,第一行没有“x==null”。对此的解释是,起初我没有在每个“真实”节点的底部使用 sentinelNode,然后我将它添加进去,所以我不需要我有的愚蠢的 null 检查。我的错误,但它仍然不起作用......
      • @gillyb:检查 null 可能是多余的,但这不是错误。我一直试图解释的是,一般来说,您的代码不应该在不确定引用是否为非空的情况下访问属性。哨兵节点是一个很好的技巧,可以避免一些空检查,但看起来你并没有成功。
      猜你喜欢
      • 1970-01-01
      • 2011-08-23
      • 2013-06-12
      • 2016-08-03
      • 2021-01-03
      • 2011-08-03
      • 2012-02-05
      • 2021-06-27
      • 2021-10-17
      相关资源
      最近更新 更多