NoneType上的红黑树AttributeError

时间:2014-10-04 00:16:30

标签: python algorithm red-black-tree nonetype

我的问题源于尝试在这两种情况下插入最后一个节点(红色节点):

enter image description here

enter image description here

这是我得到的追溯信息:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/chris/Documents/CS223/Assignment4/redblacktree.py", line 24, in insert
    self._insert(Node(data, None, 0))
  File "/home/chris/Documents/CS223/Assignment4/redblacktree.py", line 67, in _insert
    self._insertFix(z)
  File "/home/chris/Documents/CS223/Assignment4/redblacktree.py", line 71, in _insertFix
    while(z.parent.color is 1):
AttributeError: 'NoneType' object has no attribute 'color'

我使用的算法来自“算法导论”,第3版 Cormen”。

我不能为我的生活弄清楚“z.parent”如果是NoneType对象,实际上它的父节点是它上面的节点。

以下是相关代码:

class RBTree:
    __slots__ = {'_root'}

    def __init__(self):
        self._root = None

    def insert(self, data):
        if(self._root is None):
            self._root = Node(data, None, 0)
        else:
            self._insert(Node(data, None, 0))

    def _insert(self, z):
        y = None
        x = self._root
        while(x is not None):
            y = x
            if(z.data < x.data):
                x = x.left
            else:
                x = x.right
        z.parent = y
        if(y is None):
            self._root = z
        elif(z.data < y.data):
            y.left = z
        else:
            y.right = z

        z.left = None
        z.right = None
        z.color = 1
        self._insertFix(z)

    def _insertFix(self, z):
        print("Print z from _insertFix: " + str(z.data) + "\n")
        while(z.parent.color is 1):
            if(z.parent == z.parent.parent.left):
                y = z.parent.parent.right
                if(y.color is 1):
                    z.parent.color = 0
                    y.color = 0
                    z.parent.parent.color = 1
                    z = z.parent.parent
                else:
                    if(z == z.parent.right):
                        z = z.parent
                        self._rotateLeft(z)
                    z.parent.color = 0
                    z.parent.parent = 1
                    self._rotateRight(z.parent.parent)
            else:
                y = z.parent.parent.left
                if(y.color is 1):
                    z.parent.color = 0
                    y.color = 0
                    z.parent.parent.color = 1
                    z = z.parent.parent
                else:
                    if(z == z.parent.left):
                        z = z.parent
                        self._rotateRight(z)
                    z.parent.color = 0
                    z.parent.parent = 1
                    self._rotateLeft(z.parent.parent)
        self._root.color = 0

    def _rotateLeft(self, x):
        y = x.right
        x.right = y.left
        if(y.left is not None):
            y.left.parent = x
        y.parent = x.parent
        if(x.parent is not None):
            self._root = y
        elif(x == x.parent.left):
            x.parent.left = y
        else:
            x.parent.right = y
        y.left = x
        x.parent = y

    def _rotateRight(self, x):
        x = y.left
        y.left = x.right
        if(x.right is not None):
            x.right.parent = y
        x.parent = y.parent
        if(y.parent is None):
            self._root = x
        elif(y == y.parent.right):
            y.parent.right = x
        else:
            y.parent.left = x
        x.right = y
        y.parent = x

class Node:
    __slots__ = {"_left", "_right", "_parent", "_data", "_color"}

    def __init__(self, data, parent, color):
        self._left = None
        self._right = None
        self._parent = parent
        self._data = data
        self._color = color

我正在使用解释器测试我的代码,因为我还没有调用main。我想我只需要朝着正确的方向努力。

1 个答案:

答案 0 :(得分:3)

有些事情可以帮助你推动正确的工作方向......

首先,我建议在模块的主要部分放置一些驱动程序代码,以便在执行文件时执行(而不是导入)。这将允许您更紧密地迭代/调试/实验,而无需将所有内容重新键入交互式解释器。

文件末尾有这样的内容(print主要用作良好的断点位置):

if __name__ == "__main__":
    tree1 = RBTree()
    tree2 = RBTree()

    for x in (3, 5, 6, 7):
        tree1.insert(x)

    for x in (5, 3, 6, 2):
        tree2.insert(x)

    print "done"

从这些图片中可以清楚地看出,我上面使用的订单是您插入订单的确切顺序 - 根据需要更改订单(并且还包含在您的问题中以提高清晰度)。

有了这个驱动程序代码,我建议你使用调试器(pudb非常好,IMO - 它是我通常使用的调试器)以更好地了解出错的地方。这将让您逐步了解代码并了解树重新平衡的方式,以及在这种情况下z可能为None的原因。

不确定您使用调试器有多少经验,但如果您没有太多机会这样做,那么这是一个很好的开始时间 - 它通常是非常宝贵的。

关于 pudb 的一个提示:您可以通过点击<shift> + !(退出<ctrl> + d)进入交互式 Python shell,然后进入这个shell包含你当前的运行环境,所以你可以打印(或漂亮打印)变量,运行各种函数等。