二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树:
节点创建:
class TreeNode:
def __init__(self, key, value, left=None, right=None, parent=None):
# 初始化key,value,左孩子、右孩子与父亲
self.key = key
self.value = value
self.left_child = left
self.right_child = right
self.parent = parent
# 判断是否有左孩子
def has_left_child(self):
return self.left_child
# 判断是否有右孩子
def has_right_child(self):
return self.right_child
# 判断是否是左孩子
def is_left_child(self):
return self.parent and self.left_child.parent == self
# 判断是否是右孩子
def is_right_child(self):
return self.parent and self.right_child.parent == self
# 判断是否是叶子节点
def is_leaf(self):
return not (self.left_child or self.right_child)
# 判断是否是根节点
def is_root(self):
return not self.parent
# 判断是否有其他子孩子
def has_any_child(self):
return self.right_child or self.right_child
# 判断是否左孩子右孩子都存在
def has_both_child(self):
return self.left_child and self.right_child
# 将初始化的值重新赋值
def replace_data(self, key, value, lc, rc):
self.key = key
self.value = value
self.left_child = lc
self.right_child = rc
if self.has_left_child():
self.left_child.parent = self
if self.has_right_child():
self.right_child.parent = self
二叉搜索树创建:
class BinarySearchTree:
def __init__(self):
self.root = None
self.size = 0
def length(self):
return self.size
def __len__(self):
return self.length()
def __iter__(self):
return self.root.__iter__()
思路框架:
从树的根节点开始,通过搜索二叉树来比较新的键值和当前节点的键值,
- 如果新的键值小于当前节点,则搜索左子树。
- 如果新的关键大于当前节点,则搜索右子树。
当搜索不到左(或右)子树,我们在树中所处的位置就是设置新节点的位置。向树中添加一个节点,创建一个新的
TreeNode
对象并在这个点的上一个节点中插入这个对象。
# 二叉搜索树添加新元素
def put(self, key, value):
# 判断根节点是否为空
# 如果不为空,则递归添加新元素
if self.root:
self._put(key, value, self.root)
# 如果为空,则创建树节点,并设置该树节点为根节点
else:
self.root = TreeNode(key, value)
self.size = self.size + 1
def _put(self, key, value, current_node):
# 如果新的键值小于当前节点,则搜索左子树
if key < current_node.key:
# 如果有左子树,则递归创建
if current_node.has_left_child():
self._put(key, value, current_node.left_child)
# 如果没有左子树,我们在树中所处的位置就是设置新节点的位置
else:
current_node.left_child = TreeNode(key, value, parent=current_node)
# 如果新的关键大于当前节点,则搜索右子树
elif key > current_node.key:
# 如果有右子树,则递归创建
if current_node.has_right_child():
self._put(key, value, current_node.right_child)
# 如果没有右子树,我们在树中所处的位置就是设置新节点的位置
else:
current_node.right_child = TreeNode(key, value, parent=current_node)
# 实现了通过字典查询的功能
def __setitem__(self, key, value):
self.put(key, value)
思维框架:
一旦树被构造,接下来的任务就是为一个给定的键值实现检索。
get方法比 put方法更容易因为它只需递归搜索树,直到发现不匹配的叶节点或找到一个匹配的键值。
当找到一个匹配的键值后,就会返回节点中的值。
def get(self, key):
# 判断根节点是否为空
if self.root:
# 如果根节点不为空,则递归的调用内置的_get方法
res = self._get(key, self.root)
# 如果key存在,则返回节点值
if res:
return res.value
# 否则,返回None
else:
return None
# 如果根节点为空,则返回None
else:
return None
def _get(self, key, current_node):
# 如果当前节点不存在,则返回None
if not current_node:
return None
# 如果当前节点key == key,则返回当前节点
elif current_node.key == key:
return current_node
# 如果key < 当前节点的key,则搜索当前节点的左子树
elif key < current_node.key:
return self._get(key, current_node.left_child)
# 如果key > 当前节点的key,则搜索当前节点的右子树
else:
return self._get(key, current_node.right_child)
# 实现了通过字典查询的功能
def __getitem__(self, key):
return self.get(key)
# 实现了判断键是否存在于字典中,如果键在字典dict里返回true,否则返回false
def __contains__(self, key):
return True if self.get(key) else False
# 前序遍历
def preorder(self,root):
# 边界
if root is None:
return []
result = [root.value]
# 递归调用
left_item = self.preorder(root.left_child)
right_item = self.preorder(root.right_child)
return result + left_item + right_item
# 中序遍历
def inorder(self, root):
if root is None:
return []
result = [root.value]
# 递归调用
left_item = self.inorder(root.left_child)
right_item = self.inorder(root.right_child)
return left_item + result + right_item
# 后序遍历
def postorder(self, root):
if root is None:
return []
result = [root.value]
# 递归调用
left_item = self.postorder(root.left_child)
right_item = self.postorder(root.right_child)
return left_item + right_item + result
# 广度优先遍历/层次遍历
def traverse(self):
if self.root is None:
return None
# 定义一个队列来存放二叉树
q = [self.root]
res = [self.root.value]
while q != []:
pop_node = q.pop(0)
if pop_node.left_child != None:
q.append(pop_node.left_child)
res.append(pop_node.left_child.value)
if pop_node.right_child != None:
q.append(pop_node.right_child)
res.append(pop_node.right_child.value)
return res
# 简单遍历
# 使用迭代器,每次调用迭代器时,一个迭代器只返回一个节点
# python提供了一个创建迭代器非常强大的方法—yield,它的功能是创建一个可迭代的对象,因此,也叫作生成器。
# yield跟return(返回值给调用者)类似,只不过需要额外的步骤暂停函数的执行,以便下次调用函数时,为继续执行做准备
# 重写了__iter__魔法方法,借助for _ in 实现了递归
def _iter__(self):
if self:
if self.has_left_child():
for elem in self.left_child:
yield elem
yield self.key
if self.has_right_child():
for elem in self.right_child:
yield elem
思维框架:
删除一个键值。首要任务是要找到搜索树中要删除的节点。
- 如果树有一个以上的节点,我们使用
_get
方法找到需要删除的节点。- 如果树只有一个节点,这意味着我们要删除树的根,但是我们仍然要检查根的键值是否与要删除的键值匹配。
在以上两种情况下,如果没有找到该键,del操作就会报错。
def delete(self, key):
# 如果树有一个以上的节点,我们使用_get方法找到需要删除的节点
if self.size > 1:
node_to_remove = self.get(key)
# 如果找到了,则删除
if node_to_remove:
self._remove(node_to_remove)
self.size = self.size - 1
# 如果没有找到,则直接弹出错误!
else:
raise KeyError(' Error! The key isnot on the tree.')
# 如果树只有一个节点,并且根的键值与要删除的键值匹配,则直接删除根节点
if self.size == 1 and self.root.key == key:
self.root = None
self.size = self.size - 1
# size = 0,直接弹出错误!
else:
raise KeyError(' Error! The key is not on the tree.')
remove操作我们要考虑三种情况:
if current_node.is_leaf():
if current_node == current_node.parent.left_child:
current_node.parent.left_child = None
else:
current_node.parent.right_child = None
if current_node.has_left_child():
if current_node.is_left_child():
current_node.left_child.parent = current_node.parent
current_node.parent.left_child = current_node.left_child
elif current_node.is_right_child():
current_node.left_child.parent = current_node.parent
current_node.parent.right_child = current_node.left_child
else:
current_node.replace_data(current_node.key, current_node.value, current_node.left_child,
current_node.right_child)
else:
if current_node.is_left_child():
current_node.left_child.parent = current_node.parent
current_node.parent.left_child = current_node.right_child
elif current_node.is_right_child():
current_node.right_child.parent = current_node.parent
current_node.parent.right_child = current_node.right_child
current_node.replace_data(current_node.key, current_node.valuecurrent_node.left_child, current_node.right_child)
我们需要寻找一个节点,用来替换这个将要删除的节点,我们需要的这个节点能够保持现有二叉搜索树的左、右子树的关系。这个节点在树中具有第二大的键值。我们称这个节点为后继节点。
elif current_node. has_both_child():
# 找到后序节点
succ = current_node.find_successor()
# 删除后继节点
succ.splice_out()
current_node.key = succ.key
current_node.value = succ.value
当寻找后继节点时需要考虑三种情况:
# 定义找到后继节点的函数
def find_successor(self):
succ = None
if self.has_right_child():
succ = self.find_min()
else:
if self.parent:
if self.is_left_child():
succ = self.parent
else:
self.right_child = None
succ = self.parent.find_successor()
self.right_child = self
return succ
# 定义寻找子树中最小节点的函数
def find_min(self):
current = self
while self.has_left_child():
current = self.left_childreturn
return current
# 定义删除后继节点的函数
def splice_out(self):
if self.is_leaf():
if self.is_left_child():
self.parent.left_child = None
else:
self.parent.right_child = None
elif self.has_any_child():
if self.has_left_child():
if self.is_left_child():
self.parent.left_child = self.left_child
else:
self.parent.right_child = self.left_child
self.left_child.parent = self.parent
else:
if self.is_right_child():
self.parent.left_child = self.right_child
else:
self.parent.right_child = self.right_child
self.right_child.parent = self.parent
def _remove(self, current_node):
if current_node.is_leaf():
if current_node == current_node.parent.left_child:
current_node.parent.left_child = None
else:
current_node.parent.right_child = None
if current_node.has_left_child():
if current_node.is_left_child():
current_node.left_child.parent = current_node.parent
current_node.parent.left_child = current_node.left_child
elif current_node.is_right_child():
current_node.left_child.parent = current_node.parent
current_node.parent.right_child = current_node.left_child
else:
current_node.replace_data(current_node.key, current_node.value, current_node.left_child,
current_node.right_child)
else:
if current_node.is_left_child():
current_node.left_child.parent = current_node.parent
current_node.parent.left_child = current_node.right_child
elif current_node.is_right_child():
current_node.right_child.parent = current_node.parent
current_node.parent.right_child = current_node.right_child
current_node.replace_data(current_node.key, current_node.valuecurrent_node.left_child,
current_node.right_child)
elif current_node.has_both_child():
# 找到后序节点
succ = current_node.find_successor()
# 删除后继节点
succ.splice_out()
current_node.key = succ.key
current_node.value = succ.value
如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论或者私信!
235. 二叉搜索树的最近公共祖先
450. 删除二叉搜索树中的节点
669. 修剪二叉搜索树
700. 二叉搜索树中的搜索
701. 二叉搜索树中的插入操作
98. 验证二叉搜索树
99. 恢复二叉搜索树
230. 二叉搜索树中第K小的元素
501. 二叉搜索树中的众数
如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论或者私信!