zoukankan      html  css  js  c++  java
  • 算法-二叉搜索树

    二叉搜索树

    二叉搜索树的重要应用场景是组织索引,其定义如下:如一颗二叉树的每个节点对应一个关键码值,且关键码值的组织是有顺序的,例如左子节点值小于父节点值,父节点值小于右子节点值,则这颗二叉树是一颗二叉搜索树。

     

    插入的逻辑:将待插入的节点,同树根的关键码值进行比较,如果比根节点小,则进入左子树,否则进入右子树。在子树里,又与子树根进行比较,直到给该节点找到一个树叶节点。

    删除的逻辑:

    情况一:被删除的节点没有左子节点,直接用被删除节点的右子树替换被删除的节点即可。

    情况二:被删除的节点有左子节点,则把被删除节点的右子树整体挂载在左子树上,之后用被删除节点的新的左子树替换被删除的节点即可。

    在原图中,以该算法,删除节点28后的二叉搜索树如下,对应情况一:

    在原图中,以该算法,删除节点34后的二叉搜索树如下,对应情况二:

     

     代码

    #encoding=utf-8
    
    import queue
    
    class TreeNode(object):
        def __init__(self, val):
            self.value = val
            self.left = None
            self.right = None
            self.father = None
    
    class BST(object):
        def __init__(self, nodeList):
            self.root = None
            for node in nodeList:
                self.insert(node)
    
        def insert(self, node):
            father = None
            cur = self.root
            # 当树是空的时候,self.root默认是None
            while cur != None: # 找到当前可以插入节点的位置(当前树的最下层为None)
                if cur.value == node.value: # 出现和当前树中包含的值一样时,返回-1,不进行插入
                    return -1
                father = cur # 把树中当前遍历到的节点位置的对象,赋值给father变量
                if node.value < cur.value:
                    cur = cur.left # 把树中当前遍历到的节点位置的左节点作为下一个要访问的节点对象
                else:
                    cur = cur.right # 把树中当前遍历到的节点位置的右节点作为下一个要访问的节点对象
    
            node.father = father # 当树是空的,对于根节点来说,它的父节点是None
            if father == None: # 父节点是空(说明是空),把要插入的节点赋值给toot
                self.root = node
            elif node.value < father.value: # 插入的节点的值比父节点小
                father.left = node
            else: # 插入节点的值比父节点大
                father.right = node
    
        def bfs(self): # 遍历
            if self.root == None: # 空树
                return None
            retList = []
            q = queue.Queue() # 队列-先进先出
            q.put(self.root)
            while q.empty() is not True: # 队列不为空的时候才执行下面的代码
                node = q.get() # 取出一个节点值
                retList.append(node.value) # 节点值加到结果的列表retList
                if node.left != None: # 如果左节点不为None,放到队列
                    q.put(node.left)
                if node.right != None: # 如果遍历到节点的右节点也不为None,把它也放到队列里
                    q.put(node.right)
            return retList
    
        def search(self,value): # 搜索一个值
            cur = self.root
            while cur != None: # 不为None说明没有倒数的最下层
                if cur.value == value:
                    return cur # 说明找到了
                elif cur.value < value: # 要查找的值比当前遍历到的节点的值大,那么往右子树找,否则找左子树
                    cur = cur.right
                else:
                    cur = cur.left
            return None
    
        def delete(self, node): # node是树中存在的节点
            father = node.father # 获取要删除节点的父节点
            if node.left == None: # 要删除节点的左节点为None,执行下面的代码
                if father == None: # 要删除的节点是根节点的情况
                    self.root = node.right
                    if node.right != None:
                        node.right.father = None
                    elif father.left == node:
                        father.left = node.right
                        if node.right != None:
                            node.right.father = father # 因为这个节点变为了根节点,所以它的父节点就设为None
                    else:
                        father.right = node.right
                        if node.right != None:
                            node.right.father = father
                    return 1
            # 左节点不为空时,找到左子树的最下边,把右子树放到它下边
            tmpNode = node.left
            while tmpNode.right != None:# 找到待删除节点左子树下的右子树最下层节点
                tmpNode = tmpNode.right
            tmpNode.right = node.right # 把待删除元素的右子树添加到待删除节点左子树下的右子树最下层
            if node.right != None:
                node.right.father = tmpNode
    
            if father == None: # 说明删除的元素是根节点
                self.root = node.left # 左节点编程新的根节点
                node.left.father = None
            elif father.left == node:
                father.left = node.left
                node.left.father = father
            else:
                father.right = node.left
                node.left.father = father
            node = None
            return 2
    
    if __name__ == '__main__':
        varList = [24,34,5,4,8,23,45,35,28,6,29]
        nodeList = [TreeNode(var) for var in varList]
        print(nodeList)
        bst = BST(nodeList)
        print(bst)
        print(bst.bfs())
        node = bst.search(34)
        bst.delete(node)
        print(bst.bfs())
        # q = queue.LifoQueue(3)
        # q.put(1)
        # q.put(2)
        # q.put(3)
        # print(q.get())
        # print(q.get())
        # print(q.get())

    结果:

    C:UsersLenovoAppDataLocalProgramsPythonPython37python.exe D:/django/gloryroadApi/test.py
    [<__main__.TreeNode object at 0x000001E144CEC390>, <__main__.TreeNode object at 0x000001E144CEC438>, <__main__.TreeNode object at 0x000001E144CEC5F8>, <__main__.TreeNode object at 0x000001E144CEC630>, <__main__.TreeNode object at 0x000001E144CF12E8>, <__main__.TreeNode object at 0x000001E144CF1390>, <__main__.TreeNode object at 0x000001E144CF13C8>, <__main__.TreeNode object at 0x000001E144CF74E0>, <__main__.TreeNode object at 0x000001E144D65940>, <__main__.TreeNode object at 0x000001E144D65978>, <__main__.TreeNode object at 0x000001E144D659B0>]
    <__main__.BST object at 0x000001E1449D7518>
    [24, 5, 34, 4, 8, 28, 45, 6, 23, 29, 35]
    [24, 5, 28, 4, 8, 29, 6, 23, 45, 35]


  • 相关阅读:
    给伪类设置z-index= -1;
    UITextView的字数限制 及 添加自定义PlaceHolder
    UIView 翻转动画
    viewController的自动扩展属性导致TableViewGroupStyle时向上填充
    指针属性直接赋值 最好先retain 否则内存释放导致crash
    UIButton 点击后变灰
    IOS 设置透明度导致底层View始终可见
    UIDatePicker 时间选择器
    放大Button热区的方法哟
    数组套字典排序
  • 原文地址:https://www.cnblogs.com/xiaxiaoxu/p/12546280.html
Copyright © 2011-2022 走看看