我的问题源于尝试在以下两种情况下插入最后一个节点(红色节点):
这是我收到的回溯信息:
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版,作者
科曼”。
在我的一生中,我无法理解“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
。我想我只需要朝着正确的方向努力。 最佳答案
有几件事能让你在正确的方向上完成任务。。。
首先,我建议将一些驱动程序代码放在模块的主要部分,这样当文件被执行时(而不是导入时)它就会执行这将允许您更紧密地迭代/调试/实验,而无需将所有内容重新输入到交互式解释器中。
在文件的末尾有类似的内容(这里的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
的原因。不知道你有多少使用调试器的经验,但如果你没有太多的机会这样做,这是一个很好的开始时间-它往往是无价的。
关于PUBB的一个提示:您可以通过点击
<shift> + !
(退出<ctrl> + d
),将其放到交互式Python外壳中,在这个shell中包含当前的运行环境,这样您就可以打印(或漂亮打印)变量、运行各种函数等。