二叉查找树是二叉树的进化型,特点就是前序遍历得到的数组是递增关系,通俗点就是左孩子最小,父节点次之,右孩子最大
这里仿照之前写二叉树的过程来,首先定义两个类
class Node():
def __init__(self,item):
self.item=item
self.left=None
self.right=None
class Tree():
def __init__(self):
self.root=None
按二叉树的建立过程现在需要一个add方法来添加节点,二分查找树在这里就开始和二叉树有了不同
(下面简称二叉查找树BST,每次写起来太长了)
BST为了保证数中节点的大小顺序不被打乱,每次都把新的节点插入到叶子结点下,每次这么做前需要先查找到插入的位置,所以我们这里先要实现查找方法,由于BST内部节点有序,所以这里仿照二分查找
def search(self,node,item):
if not node:
return None
if node.item==item:
return node
elif node.item<item:
return self.search(node.right,item)
else:
return self.search(node.left,item)
现在来实现插入
def add(self,node,item):
if not node:
return Node(item)
if node.item==item:
return
else:
if node.item<item:
node.right=Node(item)
else:
node.left=Node(item)
return node
最难的操作来了,删除要怎么来实现,删除的节点未必是叶子结点,所以产生了删除非叶子结点后如何维护BST的问题
叶子结点和只有1个孩子的节点的删除都比较好操作,直接删除并把孩子接上原来的位置就好,问题出在左右孩子都存在的
点上
我的解决方案是这样的,找出删除节点前序遍历的前一个节点来替换,为什么这么做呢?
根据BST的特点,根节点前序遍历的前一个节点一定是左子树的最右下角节点(过几天把图补上,CSND画不了图这个就很烦)
这个节点的值一定是大于根节点左子树的所有值的,不然也不会在最右下角,同时也小于根节点所有右子树的节点下面我们来想办法实现(注意这个点未必是叶子结点,我一开始这么写结果错了很久)
def remove(self,node,item):
if not node:
return None
else:
if node.item==item:
return self.delete(node)
elif node.item<item:
return self.remove(node.right,item)
else:
return self.remove(node.left,item)
def delete(p):
if not p.left: #判断左子树位空,重接右子树
q=p
p=p.reft
del(q)
elif not p.right: #判断右子树为空,重接左子树
q=p
p=p.light
del(q)
else: #左右子树都存在
s=p.left
while s.right: #先往左,在往右边到头
q=s
s=s.right
p.item=s.item #覆盖待删除点的值
if q!=p: #这里需要判断待删除点和用来覆盖的点的关系
q.right=s.left
else:
q.left=s.left
del s
这里最难理解的是最后拼接子树的部分,这里实际上是判断了待删除节点是否为s节点的父节点,如果是的话,左孩子可以无缝连接上去,如果不是,s的左孩子就需要拼接给s的父节点作为右孩子(因为s肯定没右孩子,父节点刚好也需要一个右孩子补充失去的s节点)