一、查询
递归查询
寻找的值比根节点大,遍历右子树;
寻找的值比根节点小,遍历左子树。
def qurey(self, node, val):
if not node: # 没有节点,返回空
return None
if node.data < val:
return self.qurey(node.rchild, val)
elif node.data > val:
return self.qurey(node.lchild, val)
else:
return node
非递归查询
通过比较,指针不断向下移动,直到找到节点。
def query_no_rec(self, val):
p = self.root
while p:
if p.data < val:
p = p.rchild
elif p.data > val:
p = p.lchild
else:
return p
return None
二、删除
删除操作思路
删除操作比较难,需要考虑三种情况
1、删除叶子节点:直接删除
2、如果删除的节点只有一个孩子:将此节点的孩子与父亲链接,然后删除此节点。(如果删除的根节点只有一个孩子,删除根节点后,要重新更新一下根节点)
3、如果要删除的节点有两个孩子,将其右子树的最小节点(该节点最多有一个右孩子)替换当前节点,并删除。
详细解释
第一种情况:叶子节点
如果只有一个根节点,那么把根节点置为空就算删除。
如果是叶子节点,将该节点的父节点指向空,即为删除这个节点。ps:需要判断是左孩子还是右孩子
def __remove_node_1(self, node):
# 情况1:node是叶子节点
if not node.parent:
self.root = None
if node == node.parent.lchild:
node.parent.lchild = None
else:
node.parent.rchild = None
第二种情况:2.1 只有一个左孩子
2.1.1
如果是删除根节点,那么将根节点直接指向左孩子即可。
2.1.2
如果是树中的某一个左孩子,且只有一个左孩子,那么将该节点的父节点指向该节点的左孩子,并将指向该节点左孩子的指针指向该节点的父节点。
这个过程有点绕,多理解理解就好了,下面配图帮助理解。图中蓝线是指针变化后应该指向的位置。
2.1.3
如果是树中的某一个右孩子,且只有一个左孩子,那么将该节点的父节点指向该节点的左孩子,并将指向该节点左孩子的指针指向该节点的父节点。
实现代码
def __remove_node_21(self, node):
# 情况2.1:node只有一个左孩子
if not node.parent:
self.root = node.lchild
node.parent.lchild = None
elif node == node.parent.lchild:
node.parent.lchild = node.lchild
node.lchild.parent = node.parent
else:
node.parent.rchild = node.lchild
node.lchild.parent = node.parent
第二种情况:2.2 只有一个右孩子
2.2.1
如果是删除根节点,那么将根节点直接指向右孩子即可。
2.2.2
如果是树中的某一个左孩子,且只有一个右孩子,那么将该节点的父节点指向该节点的右孩子,并将指向该节点右孩子的指针指向该节点的父节点。
2.2.3
如果是树中的某一个右孩子,且只有一个右孩子,那么将该节点的父节点指向该节点的右孩子,并将指向该节点右孩子的指针指向该节点的父节点。
实现代码
def __remove_node_22(self, node):
# 情况2.2:node只有一个右孩子
if not node.parent:
self.root = node.rchild
elif node == node.parent.lchild:
node.parent.lchild = node.rchild
node.rchild.parent = node.parent
else:
node.parent.rchild = node.rchild
node.rchild.parent = node.parent
第三种情况:左右两个孩子都有
3.1 在右子树中寻找最小的数。因为你删除的那个节点需要有数字替代,那么就是右子树中最小的那个数。
3.2 for循环遍历右子树的左孩子,找到最小的值。
3.3 把找到的最小的数替换到要删除的节点位置。
3.4 判断我们找到的最小数是只有右孩子的情况还是叶子节点的情况。这个节点不可能会有左孩子的情况,因为我们寻找最小数的已经找到最后一个左孩子了。
实现代码
min_node = node.rchild
while min_node.lchild:
min_node = min_node.lchild
node.data = min_node.data
# 删除min_node节点
if min_node.rchild:
self.__remove_node_22(node)
else:
self.__remove_node_1(node)
删除操作整个实现
没有右孩子就是只有一个左孩子
没有左孩子就是只有一个右孩子
def delete(self, val):
if self.root: # 不是空树查询节点
node = self.query_no_rec(val)
if not node:
return False
if not node.lchild and not node.rchild: # 1. 叶子节点
self.__remove_node_1(node)
elif not node.rchild: # 2.1只有一个左孩子
self.__remove_node_21(node)
elif not node.lchild: # 2.3 只有一个右孩子
self.__remove_node_22(node)
else: # 3.两个孩子都有
min_node = node.rchild
while min_node.lchild:
min_node = min_node.lchild
node.data = min_node.data
# 删除min_node节点
if min_node.rchild:
self.__remove_node_22(node)
else:
self.__remove_node_1(node)
ok这就是查询和删除操作!代码一定要自己手敲!多动手!勤思考!一定会有进步的!