一、查询
递归查询
寻找的值比根节点大,遍历右子树;
寻找的值比根节点小,遍历左子树。
def qurey(self, node, val):if not node: # 没有节点,返回空return Noneif 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.rootwhile p:if p.data < val:p = p.rchildelif p.data > val:p = p.lchildelse:return preturn None
二、删除
删除操作思路
删除操作比较难,需要考虑三种情况
1、删除叶子节点:直接删除
2、如果删除的节点只有一个孩子:将此节点的孩子与父亲链接,然后删除此节点。(如果删除的根节点只有一个孩子,删除根节点后,要重新更新一下根节点)
3、如果要删除的节点有两个孩子,将其右子树的最小节点(该节点最多有一个右孩子)替换当前节点,并删除。
详细解释
第一种情况:叶子节点
如果只有一个根节点,那么把根节点置为空就算删除。
如果是叶子节点,将该节点的父节点指向空,即为删除这个节点。ps:需要判断是左孩子还是右孩子
def __remove_node_1(self, node):# 情况1:node是叶子节点if not node.parent:self.root = Noneif node == node.parent.lchild:node.parent.lchild = Noneelse: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.lchildnode.parent.lchild = Noneelif node == node.parent.lchild:node.parent.lchild = node.lchildnode.lchild.parent = node.parentelse:node.parent.rchild = node.lchildnode.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.rchildelif node == node.parent.lchild:node.parent.lchild = node.rchildnode.rchild.parent = node.parentelse:node.parent.rchild = node.rchildnode.rchild.parent = node.parent
第三种情况:左右两个孩子都有
3.1 在右子树中寻找最小的数。因为你删除的那个节点需要有数字替代,那么就是右子树中最小的那个数。
3.2 for循环遍历右子树的左孩子,找到最小的值。
3.3 把找到的最小的数替换到要删除的节点位置。
3.4 判断我们找到的最小数是只有右孩子的情况还是叶子节点的情况。这个节点不可能会有左孩子的情况,因为我们寻找最小数的已经找到最后一个左孩子了。
实现代码
min_node = node.rchildwhile min_node.lchild:min_node = min_node.lchildnode.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 Falseif 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.rchildwhile min_node.lchild:min_node = min_node.lchildnode.data = min_node.data# 删除min_node节点if min_node.rchild:self.__remove_node_22(node)else:self.__remove_node_1(node)
ok这就是查询和删除操作!代码一定要自己手敲!多动手!勤思考!一定会有进步的!