python实现二叉查找树

二叉查找树

二叉查找树,也称二叉搜索树,或二叉排序树。其定义也比较简单,要么是一颗空树,要么就是具有如下性质的二叉树:

  • 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 任意节点的左、右子树也分别为二叉查找树;
  • 没有键值相等的节点。
    二叉搜索树

二叉查找树的增删改查

首先创建节点类,包括值,左子节点,右子节点,三个属性

class Node():    
    def __init__(self, value, left=None, right=None):        
        self.value = value        
        self.left = left        
        self.right = righ

创建树类,包括增,删,查,取最大,取最小,遍历(中序遍历)方法

增:

  • 首先判断是否存在根节点,如果不存在则直接创建节点,作为根节点返回
  • 判断输入的值是否大于根节点的值,如果大于,则将其右子节点作为根节点;如果小于根节点的值,则将左子节点作为根节点的值,循环上述操作,直到所查询的根节点为None,创建Node实例,作为其上一轮遍历节点的子节点
class Tree:    
    def insert(self, value, root):        
        if root == None:            
            root = Node(value)        
        elif value > root.value:            
            root.right = self.insert(value, root.right)        
        else:            
            root.left = self.insert(value, root.left)        
            return root    

查:

  • 首先判断根节点是否存在,如果不存在则返回-1
  • 用被查找的值与根节点的值进行比较,如果相等则返回根节点,如果大于根节点的值,则将其右子节点作为根几点,如果小于根节点的值,则将左子节点作为根节点,继续查找
  • 如果最终root的值为-1则表示该值不存在返回-1
def query(self, value, root):        
    if root == None:            
        return -1        
    elif value > root.value:            
        return self.query(value, root.right)        
    elif value < root.value:            
        return self.query(value, root.left)        
    else:            
        return root    

寻找最大、最小值

  • 由于二叉查找树的右子节点的值总是大于父节点,所以只要不停地寻找根节点的右子,右子孙节点即可
  • 如果右子、孙节点为None,则说明该节点的值即为树种的最大值
  • 最小值与最大值相反
def findmax(self, root):
    if root == None:
        return
    elif root.right:
        return self.findmax(root.right)
    else:
        return root

def findmine(self, root):
    if root == None:
        return
    elif root.left:
        return self.findmine(root.left)
    else:
        return root

删:

  • 首先判断该树是否为空
  • 在树中查找该节点,如果不存在则直接返回
  • 从根节点开始,查找到该节点,分三种情况
    • 如果该节点没有子节点,则直接将其删除
    • 如果该节点存在左子节点或右子节点,则将该节点的父节点指向该节点的左子节点或右子节点
    • 如果该节点同时存在左子节点和右子节点,则互换该节点和该节点右子树中的最小值的节点(或互换该节点和该节点左子树的最大值),以互换该节点和右子树种的最大值为例,具体过程如下
      • 找到右子树中的最小值对应节点
      • 该节点右子树最小值赋值给该节点,不改变该节点的left,right
      • 删除右子树种的最小值节点,重复上述步骤
def delNode(self,root, value):
    '''删除二叉搜索树中值为value的点'''
    if self.query(value, root) == -1:
        return
    if root == None:
        return
    if value < root.value:
        root.left = self.delNode(value,root.left)
    elif value > root.value:
        root.right = self.delNode(root.right,value)
    # 当value == root.value时,分为三种情况:只有左子树或者只有右子树、有左右子树、即无左子树又无右子树
    else:
        if root.left and root.right:
            # 既有左子树又有右子树,则需找到右子树中最小值节点
            temp = self.findmine(root.right)
            root.value = temp.value
            # 再把右子树中最小值节点删除
            root.right = self.delNode(root.right,temp.value)
        elif root.right == None and root.left == None:
            # 左右子树都为空
            root = None
        elif root.right == None:
            # 只有左子树
            root = root.left
        elif root.left == None:
            # 只有右子树
            root = root.right
    return root

中序遍历

# 递归中序遍历
def pre_order(self, root):
     if root == None:
         return
     self.pre_order(root.left)
     print(root.value)
     self.pre_order(root.right)
# 迭代中序遍历
def pre_oder_2(root):
	# ans列表用于存储排序后的数据,stack为栈存储逆序的ans,先进后出
    ans,stack = [],[]
    cur = root
    while cur or stack:
        if cur:
        	# 将根节点左子树压入栈中
            stack.append(cur)
            cur = cur.left
        else:
        	# 取最左侧节点,即为最小值
            cur = stack.pop()
            ans.append(cur)
            # 取最左侧节点的右子节点,如果存在右子树,则将其压入栈中
            cur = cur.right

获取树的高度

分别获取左子树和右子树的高度,取二者较大者,再加1即为整个树的高度

def get_depth(self, root):
    if root == None:
        return 0
    nright = self.get_depth(root.right)
    nleft = self.get_depth(root.left)
    return max(nleft, nright) + 1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值