一、概念
二叉搜索树(Binary Search Tree)是一颗二叉树且满足性质:设x是二叉树的一个节点。如果y树x左子树的一个节点,那么;如果y是x右子树的一个节点,那么。
用通俗一点的话来说就是在一棵二叉树中,左子树所有节点都比它的根节点小,右子树所有节点都比它的根节点大。(如图所示)
所以当我们要定义一个BST树时,用双链表来做就要想到要初始化的东西:
1. 数据域data 0
2. 树的左孩子和右孩子(lchild/rchild)
3. 他们的双亲parent
定义BST树代码如下:
class BSTreeNode: def __init__(self): self.data=data self.lchild=None #左孩子 self.rchild=None #右孩子 self.parent=None
二、搜索二叉树的插入
递归插入代码思路:
1. 判断当前节点是否为空,是的话就直接插入结点
2. 如果当前节点不为空,则有三种判断
当前节点大于插入的结点,插入的结点应放在当前结点的左边
当前节点小于插入的结点,插入的结点应放在当前节点的右边
当前节点等于插入的结点,这个代码可以不执行,可以不写,如果想优化代码可以写如果当前及诶点等于插入的结点会怎样怎样
3. 最后别忘了绑定要插入的结点的双亲
代码如下:
# 递归插入函数 node结点位置 val为要插入的结点 def insert(self, node, val): # 如果node是空,有空间,可直接插入结点 if not node: node = BSTreeNode(val) # 如果node不为空则有两种判断 插入的结点值小于(大于)node结点值 elif val < node.data: node.lchild = self.insert(node.lchild, val) # 递归查空左孩子,给左孩子赋值 node.lchild.parent = node # 绑定左孩子的双亲 elif val > node.data: node.rchild = self.insert(node.rchild, val) node.rchild.parent = node # 其实这里还有一个else val=node.data , 这个默认我们找到了就不找了,所以不做什么回应 # 如果想优化代码可以写上else return node
非递归插入代码思路如下:
1. 定义一个变量来保存这棵树的根
2. 判断该树是否为空,判断方法为判断根是否存在,如果是空,直接将要插入的结点插入根节点
3. 不是空树,则有三种判断
当前节点大于根节点,插入的结点应放在根节点的左边,所以要判断根节点有没有左子树,有左子树的话就再找它的左子树的下一个左子树,直到找到空节点进行插入
当前节点小于根节点,插入的结点应放在根节点的右边,所以要判断根节点有没有右子树,有右子树的话就再找它的右子树的下一个右子树,直到找到空节点进行插入
当前节点等于插入的结点,代码可以不写,也可以写,这里不写
代码如下:
def insert_not_rec(self,val): p=self.root #如果树是空树 if not p: self.root=BSTreeNode(val) return #递归函数中因为直接判断是空树就直接返回了,不用特殊处理,但是这里需要特殊处理,因为这里不是递归 # 如果不是空树: while True: if val<p.data: # 判断左子树是否为空,是空就直接插入,不是空就往下一个左子树找空间 if p.lchild: #如果存在左子树,左子树不为空 p=p.lchild else: p.lchild=BSTreeNode(val) p.lchild.parent=p return elif val>p.data: if p.rchild: #如果存在右子树,右子树不为空 p=p.rchild else: p.rchild=BSTreeNode(val) p.rchild.parent=p return else: #如果val=p.data return
总体代码如下:
因为递归执行效率较慢,所以改代码使用非递归执行,因为再创建了另一个类,所以需要初始化一下树的根
class BSTreeNode: def __init__(self, data): self.data = data self.lchild = None # 左孩子 self.rchild = None # 右孩子 self.parent = None class BST: # 初始化树的根 def __init__(self,li=None): self.root = None if li: for val in li : self.insert_not_rec(val) # 递归插入函数 node结点位置 val为要插入的结点 def insert(self, node, val): # 如果node是空,有空间,可直接插入结点 if not node: node = BSTreeNode(val) # 如果node不为空则有两种判断 插入的结点值小于(大于)node结点值 elif val < node.data: node.lchild = self.insert(node.lchild, val) # 递归查空左孩子,给左孩子赋值 node.lchild.parent = node # 绑定左孩子的双亲 elif val > node.data: node.rchild = self.insert(node.rchild, val) node.rchild.parent = node # 其实这里还有一个else val=node.data , 这个默认我们找到了就不找了,所以不做什么回应 # 如果想优化代码可以写上else return node # 非递归插入函数 参数只需要一个插入的结点 def insert_not_rec(self,val): p=self.root #如果树是空树 if not p: self.root=BSTreeNode(val) return #递归函数中因为直接判断是空树就直接返回了,不用特殊处理,但是这里需要特殊处理,因为这里不是递归 # 如果不是空树: while True: if val<p.data: # 判断左子树是否为空,是空就直接插入,不是空就往下一个左子树找空间 if p.lchild: #如果存在左子树,左子树不为空 p=p.lchild else: p.lchild=BSTreeNode(val) p.lchild.parent=p return elif val>p.data: if p.rchild: #如果存在右子树,右子树不为空 p=p.rchild else: p.rchild=BSTreeNode(val) p.rchild.parent=p return else: #如果val=p.data return def pre_order(self,root): if root: print(root.data, end=",") self.pre_order(root.lchild) self.pre_order(root.rchild) def in_order(self,root): if root: self.in_order(root.lchild) print(root.data, end=",") self.in_order(root.rchild) def post_order(self,root): if root: self.post_order(root.lchild) self.post_order(root.rchild) print(root.data, end=",") tree=BST([4,6,7,9,2,1,3,5,8]) tree.pre_order(tree.root) print("") tree.in_order(tree.root) print("") tree.pre_order(tree.root)
结果输出为:
4,2,1,3,6,5,7,9,8, 1,2,3,4,5,6,7,8,9, 4,2,1,3,6,5,7,9,8,
可以看出,BST树的中序遍历一定是顺序的,记住这不是巧合就行