二叉搜索树
二叉搜索树的重要应用场景是组织索引,其定义如下:如一颗二叉树的每个节点对应一个关键码值,且关键码值的组织是有顺序的,例如左子节点值小于父节点值,父节点值小于右子节点值,则这颗二叉树是一颗二叉搜索树。
插入的逻辑:将待插入的节点,同树根的关键码值进行比较,如果比根节点小,则进入左子树,否则进入右子树。在子树里,又与子树根进行比较,直到给该节点找到一个树叶节点。
删除的逻辑:
情况一:被删除的节点没有左子节点,直接用被删除节点的右子树替换被删除的节点即可。
情况二:被删除的节点有左子节点,则把被删除节点的右子树整体挂载在左子树上,之后用被删除节点的新的左子树替换被删除的节点即可。
在原图中,以该算法,删除节点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]