【问题标题】:Red-Black tree implementation in Python simply colours all leaves red, why is this?Python中的红黑树实现只是将所有叶子都涂成红色,这是为什么呢?
【发布时间】:2017-07-17 14:09:05
【问题描述】:

我有在 python 中实现红黑树的代码。但是,当我运行我的代码时,似乎它所做的只是像插入常规 BST 一样插入值,然后将所有内部顶点涂成红色。这是家庭作业的练习作业,但我被困住了,无处可去。

这是我的实现:

class BinaryTreeVertex(object):
    def __init__(self, data=None, isALeaf=True, colour='r', left=None, right=None):
        # Assume user will pass a left & right ONLY IF isALeaf=False
        self.data = data
        self.isALeaf = isALeaf
        self.colour = colour
        self.left = left
        self.right = right

class BinarySearchTree(object):
    def __init__(self, root=None):
        self.root = BinaryTreeVertex()

    def insert(self, value):
        self.root = recInsert(self.root, value)
        self.root.colour = 'b'

    def searchPath(self, val):
        path = []
        node = self.root
        while node is not None:
            path.append(node.data)
            if val < node.data:
                node = node.left
            elif val > node.data:
                node = node.right
            else:
                node = None
        return path

    def totalDepth(self):
        if self.root.isALeaf:
            return 0
        else:
            return recTotalDepth(self.root)

# returns the depth of a given node
# plus it's children's depths
def recTotalDepth(node, currDepth=0):
    if node.isALeaf:
        return 0
    else:
        leftDepth = 0
        rightDepth = 0
        if node.left is not None:
            leftDepth = recTotalDepth(node.left, currDepth+1)
        if node.right is not None:
            rightDepth = recTotalDepth(node.right, currDepth+1)

        return leftDepth + currDepth + rightDepth

# print a sideways representation of the BinarySearchTree
# Up = right, down = left
def printTree(node, indent=0):
    if node.isALeaf:
        return
    else:
        if node.right is not None:
            printTree(node.right, indent+4)
        print(" "*indent + str(node.data) + node.colour)
        if node.left is not None:
            printTree(node.left, indent+4)


# Insert a value into the binary search tree
def recInsert(node, value):
        if node.isALeaf:
            # Set the data to value, the colour to red, give the vertex two
            # empty leaves coloured black
            return BinaryTreeVertex(value, False, 'r', BinaryTreeVertex(None, True, 'b'), BinaryTreeVertex(None, True, 'b'))
        elif value > node.data:
            node.right = recInsert(node.right, value)
            # check for balance
            if node.colour == 'r':
                # no balance check @ red vertices
                return node
            else: # node.colour is black
                # Grandparents/Parents will handle balance of red vertices
                # We must only perform balances at black vertices
                if node.right.colour == 'r':
                    # right child is red, possibility for red-red conflict
                    if node.right.right.colour == 'r':
                        # red-red conflict on the right-right children
                        return rightRightFix(node)
                    elif node.right.left.colour == 'r':
                        # red-red conflict on the right-left children
                        return rightLeftFix(node)
                    else:
                        # no red-red conflicts
                        return node
                else:
                    # right child is black, no fixing needed
                    return node
        else: # value < self.data
            node.left = recInsert(node.left, value)
            # check for balance
            if node.colour == 'r':
                # no balance checks @ red vertices
                return node
            else: # node.colour == 'b'
                # Grandparents/Parents will handle balance of red vertices
                # We must only perform balances at black vertices
                if node.left.colour == 'r':
                    # left child is red, possibility for red-red conflict
                    if node.left.left.colour == 'r':
                        # red-red conflict on the left-left children
                        return leftLeftFix(node)
                    elif node.left.right.colour == 'r':
                        # red-red conflict on the left-right children
                        return leftRightFix(node)
                    else:
                        # no red-red conflicts
                        return node
                else:
                    # left child is black, no fixing needed
                    return node

def rightRightFix(node):
    # red-red conflict on right-right children
    child = node.right
    sib = node.left
    if sib.colour == 'r':
        # no need for rotation, just recolour
        child.colour == 'b'
        sib.colour == 'b'
        node.colour == 'r'
        return node
    else:
        # sib's colour is black, single rot
        # fix pointers first
        node.right = child.left
        child.left = node
        # fix colours
        child.colour = 'b'
        node.colour = 'r'
        # make the new root, which is now child
        return child

def rightLeftFix(node):
    # red-red conflict on right-left children
    child = node.right
    sib = node.left
    if sib.colour == 'r':
        # no need for rotation, just recolour
        child.colour == 'b'
        sib.colour == 'b'
        node.colour == 'r'
        return node
    else:
        # sib's colour is black, double rot
        # fix the pointers
        grandchild = child.left
        child.left = grandchild.right
        node.right = grandchild.left
        grandchild.left = node
        grandchild.right = child
        # fix the colours
        grandchild.colour == 'b'
        node.colour = 'r'
        # return the new root, which is now grandchild
        return grandchild

def leftLeftFix(node):
    # red-red conflict on right-right children
    child = node.left
    sib = node.right
    if sib.colour == 'r':
        # no need for rotation, just recolour
        child.colour == 'b'
        sib.colour == 'b'
        node.colour == 'r'
        return node
    else:
        # sib's colour is black, single rot
        # fix pointers first
        node.left = child.right
        child.right = node
        # fix colours
        child.colour = 'b'
        node.colour = 'r'
        # make the new root, which is now child
        return child

def leftRightFix(node):
    # red-red conflict on left-right children
    child = node.left
    sib = node.right
    if sib.colour == 'r':
        # no need for rotation, just recolour
        child.colour == 'b'
        sib.colour == 'b'
        node.colour == 'r'
        return node
    else:
        # sib's colour is black, double rot
        # fix the pointers
        grandchild = child.right
        child.right = grandchild.left
        node.left = grandchild.right
        grandchild.right = node
        grandchild.left = child
        # fix the colours
        grandchild.colour == 'b'
        node.colour = 'r'
        # return the new root, which is now grandchild
        return grandchild


def main():
    myTree = BinarySearchTree()
    myList = [13,42,3,6,23,32,72,90,1,10,26,85,88,97,73,80,35,36,88,34,12,92,100,143,123,124,125,126,127,128]


    for v in myList:
        myTree.insert(v)

    printTree(myTree.root)
    print(myTree.searchPath(12))

    print(myTree.totalDepth())

    myTree2 = BinarySearchTree()
    myList2 = [6, 10, 20, 8, 3]


    for v in myList2:
        myTree2.insert(v)

    printTree(myTree2.root)
    print(myTree2.searchPath(6))

    print(myTree2.totalDepth())

main()

【问题讨论】:

  • 找到错误的一个好方法是为您的代码编写测试用例。首先编写测试最简单的情况,然后一旦可行,就为更复杂/极端情况添加更多测试
  • 所以从我的简单测试中,我收集到我的“修复”功能实际上并没有重新着色我的顶点。

标签: python data-structures binary-search-tree red-black-tree


【解决方案1】:

提供的源代码中解释为什么您的算法“实际上没有重新着色我的顶点”的主要问题是由于分配错误。

在所有函数 rightRightFix()rightLeftFix()leftLeftFix()leftRightFix() 中,神秘地某些颜色分配 (child.colour = 'b') 已被编码为比较 (child.colour == 'b')。

解决方案 - 只需替换 14 个错误的复制/粘贴分配错误即可。

改正后,您的红黑树算法完美运行。

小错误 - 在BinarySearchTree::searchPath() 中找不到值。

当搜索到的值不存在时,你会得到:

TypeError: unorderable types: int() &lt; NoneType()

这是由于使用了未初始化的Leaf节点。

def searchPath(self, val):
    path = []
    node = self.root
    while node is not None:
        path.append(node.data)
        # break the while when node is the leave
        if (node.isALeaf == True):
            break
        if val < node.data:
            node = node.left
        elif val > node.data:
            node = node.right
        else:
            node = None
    return path

在这种情况下,返回的搜索路径将以 'None' => 未找到

输入:print(myTree.searchPath(102))

输出:[72, 88, 100, 124, 123, None]

【讨论】:

    猜你喜欢
    • 2011-09-18
    • 2013-03-13
    • 2014-09-23
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    • 2020-05-27
    • 2023-03-14
    相关资源
    最近更新 更多