如何在Python中实现二进制搜索树?

cho*_*him 35 python oop class binary-search-tree data-structures

这是我到目前为止所得到的但它不起作用:

class Node:
    rChild,lChild,data = None,None,None

    def __init__(self,key):
        self.rChild = None
        self.lChild = None
        self.data = key

class Tree:
    root,size = None,0
    def __init__(self):
        self.root = None
        self.size = 0

    def insert(self,node,someNumber):
        if node is None:
            node = Node(someNumber)
        else:
            if node.data > someNumber:
                self.insert(node.rchild,someNumber)
            else:
                self.insert(node.rchild, someNumber)
        return

def main():
    t = Tree()
    t.root = Node(4)
    t.root.rchild = Node(5)
    print t.root.data #this works
    print t.root.rchild.data #this works too
    t = Tree()
    t.insert(t.root,4)
    t.insert(t.root,5)
    print t.root.data #this fails
    print t.root.rchild.data #this fails too

if __name__ == '__main__':
     main()
Run Code Online (Sandbox Code Playgroud)

DTi*_*ing 61

以下是二进制插入的快速示例:

class Node:
    def __init__(self, val):
        self.l_child = None
        self.r_child = None
        self.data = val

def binary_insert(root, node):
    if root is None:
        root = node
    else:
        if root.data > node.data:
            if root.l_child is None:
                root.l_child = node
            else:
                binary_insert(root.l_child, node)
        else:
            if root.r_child is None:
                root.r_child = node
            else:
                binary_insert(root.r_child, node)

def in_order_print(root):
    if not root:
        return
    in_order_print(root.l_child)
    print root.data
    in_order_print(root.r_child)

def pre_order_print(root):
    if not root:
        return        
    print root.data
    pre_order_print(root.l_child)
    pre_order_print(root.r_child)    
Run Code Online (Sandbox Code Playgroud)
r = Node(3)
binary_insert(r, Node(7))
binary_insert(r, Node(1))
binary_insert(r, Node(5))
Run Code Online (Sandbox Code Playgroud)
     3
    / \
   1   7
      /
     5
Run Code Online (Sandbox Code Playgroud)
print "in order:"
in_order_print(r)

print "pre order"
pre_order_print(r)

in order:
1
3
5
7
pre order
3
1
7
5
Run Code Online (Sandbox Code Playgroud)

  • @ealeon nope它不会:如果删除检查,则此代码不会将任何新节点附加到树中.无用的部分是`如果root是None:root = None`.此代码的另一个问题是它允许重复.这可以修复`else`更改为`elif root.data <node.data`. (2认同)

Hug*_*ell 10

class Node: 
    rChild,lChild,data = None,None,None
Run Code Online (Sandbox Code Playgroud)

这是错误的 - 它使您的变量成为类变量 - 也就是说,每个Node实例都使用相同的值(更改任何节点的rChild会为所有节点更改它!).这显然不是你想要的; 尝试

class Node: 
    def __init__(self, key):
        self.rChild = None
        self.lChild = None
        self.data = key
Run Code Online (Sandbox Code Playgroud)

现在每个节点都有自己的一组变量.这同样适用于您对Tree的定义,

class Tree:
    root,size = None,0    # <- lose this line!
    def __init__(self):
        self.root = None
        self.size = 0
Run Code Online (Sandbox Code Playgroud)

此外,每个类应该是一个派生自"object"类的"new-style"类,并且应该链回到object .__ init __():

class Node(object): 
    def __init__(self, data, rChild=None, lChild=None):
        super(Node,self).__init__()
        self.data   = data
        self.rChild = rChild
        self.lChild = lChild

class Tree(object):
    def __init__(self):
        super(Tree,self).__init__()
        self.root = None
        self.size = 0
Run Code Online (Sandbox Code Playgroud)

另外,main()缩进太多 - 如图所示,它是Tree的一种方法,它是不可调用的,因为它不接受自身参数.

此外,您正在直接修改对象的数据(t.root = Node(4))哪种破坏封装(首先是具有类的整个点); 你应该做更像的事情

def main():
    t = Tree()
    t.add(4)    # <- let the tree create a data Node and insert it
    t.add(5)
Run Code Online (Sandbox Code Playgroud)


Ara*_*yan 7

class BST:
    def __init__(self, val=None):
        self.left = None
        self.right = None
        self.val = val

    def __str__(self):
        return "[%s, %s, %s]" % (self.left, str(self.val), self.right)

    def isEmpty(self):
        return self.left == self.right == self.val == None

    def insert(self, val):
        if self.isEmpty():
            self.val = val
        elif val < self.val:
            if self.left is None:
                self.left = BST(val)
            else:
                self.left.insert(val)
        else:
            if self.right is None:
                self.right = BST(val)
            else:
                self.right.insert(val)

a = BST(1)
a.insert(2)
a.insert(3)
a.insert(0)
print a
Run Code Online (Sandbox Code Playgroud)


cho*_*him 6

class Node:
    rChild,lChild,parent,data = None,None,None,0    

def __init__(self,key):
    self.rChild = None
    self.lChild = None
    self.parent = None
    self.data = key 

class Tree:
    root,size = None,0
    def __init__(self):
        self.root = None
        self.size = 0
    def insert(self,someNumber):
        self.size = self.size+1
        if self.root is None:
            self.root = Node(someNumber)
        else:
            self.insertWithNode(self.root, someNumber)    

    def insertWithNode(self,node,someNumber):
        if node.lChild is None and node.rChild is None:#external node
            if someNumber > node.data:
                newNode = Node(someNumber)
                node.rChild = newNode
                newNode.parent = node
            else:
                newNode = Node(someNumber)
                node.lChild = newNode
                newNode.parent = node
        else: #not external
            if someNumber > node.data:
                if node.rChild is not None:
                    self.insertWithNode(node.rChild, someNumber)
                else: #if empty node
                    newNode = Node(someNumber)
                    node.rChild = newNode
                    newNode.parent = node 
            else:
                if node.lChild is not None:
                    self.insertWithNode(node.lChild, someNumber)
                else:
                    newNode = Node(someNumber)
                    node.lChild = newNode
                    newNode.parent = node                    

    def printTree(self,someNode):
        if someNode is None:
            pass
        else:
            self.printTree(someNode.lChild)
            print someNode.data
            self.printTree(someNode.rChild)

def main():  
    t = Tree()
    t.insert(5)  
    t.insert(3)
    t.insert(7)
    t.insert(4)
    t.insert(2)
    t.insert(1)
    t.insert(6)
    t.printTree(t.root)

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

我的解决方案


Joh*_*hin 5

Op的Tree.insert方法有资格获得"本周大赢家"奖 - 它没有插入任何内容.它创建一个未附加到任何其他节点的节点(不是有任何节点将其附加到),然后在方法返回时删除创建的节点.

为了@Hugh Bothwell的启发:

>>> class Foo(object):
...    bar = None
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar
>>> a.bar = 42
>>> b.bar
>>> b.bar = 666
>>> a.bar
42
>>> b.bar
666
>>>
Run Code Online (Sandbox Code Playgroud)

  • "Gross Misnomer"lol感谢您指出错误. (2认同)

Kur*_*eek 5

接受的答案忽略了为每个插入的节点设置父属性,否则就无法实现在O ( hsuccessor ) 时间内在有序树中查找后继者的方法,其中h是树的高度(与到步行所需的O ( n ) 时间)。

下面是基于 Cormen 等人的《算法简介》中给出的伪代码的实现,包括parent属性和方法的分配successor

class Node(object):
    def __init__(self, key):
        self.key = key
        self.left = None
        self.right = None
        self.parent = None


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

    def insert(self, z):
        y = None
        x = self.root
        while x is not None:
            y = x
            if z.key < x.key:
                x = x.left
            else:
                x = x.right
        z.parent = y
        if y is None:
            self.root = z       # Tree was empty
        elif z.key < y.key:
            y.left = z
        else:
            y.right = z

    @staticmethod
    def minimum(x):
        while x.left is not None:
            x = x.left
        return x

    @staticmethod
    def successor(x):
        if x.right is not None:
            return Tree.minimum(x.right)
        y = x.parent
        while y is not None and x == y.right:
            x = y
            y = y.parent
        return y
Run Code Online (Sandbox Code Playgroud)

以下是一些测试,表明树的行为符合DTing给出的示例的预期:

import pytest

@pytest.fixture
def tree():
    t = Tree()
    t.insert(Node(3))
    t.insert(Node(1))
    t.insert(Node(7))
    t.insert(Node(5))
    return t

def test_tree_insert(tree):
    assert tree.root.key == 3
    assert tree.root.left.key == 1
    assert tree.root.right.key == 7
    assert tree.root.right.left.key == 5

def test_tree_successor(tree):
    assert Tree.successor(tree.root.left).key == 3
    assert Tree.successor(tree.root.right.left).key == 7

if __name__ == "__main__":
    pytest.main([__file__])
Run Code Online (Sandbox Code Playgroud)