二叉排序树与AVL树

本文介绍了二叉排序树的定义、查找、插入和删除操作,并深入讲解了AVL树的平衡因子、最小不平衡子树的概念,以及插入和删除操作的实现原理和平衡调整策略。通过示例说明了四种不同情况下的旋转操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉排序树

定义:二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
 (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
 (2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
 (3)左、右子树也分别为二叉排序树;

算法思想

查找:查找 k e y key key值,由二叉排序树的定义可以知道,在进行查找操作时,可以先与根节点比较,若比根节点的值小则再与左子树的根节点比较,若比根节点的值大则再与右子树的根节点比较,若与根节点的值相等则查找结束,从描述可以看出,这是一个典型的递归操作。
插入:插入 k e y key key值,先对于二叉排序树进行 k e y key key值的查找,若没有 k e y key key值再进行插入。对于插入操作,先确定 k e y key key值应该插入的位置,当然 k e y key key值插入进去后是成为二叉排序树的叶子节点。对于查找插入位置,可以设一个新变量 c u r r e n t current current来记录在搜寻合适位置时,当前的节点位置。
删除:删除操作是二叉排序树中相对而言最复杂的操作。删除 k e y key key值节点 T T T,先对于二叉排序树进行 k e y key key值查找,若存在 k e y key key值再进行删除。对于删除操作,一共有三种情况,若删除的节点 T T T是树中的叶子节点,则直接删除即可;若删除的节点 T T T有且仅有一个孩子节点,则直接将 T T T的双亲节点与 T T T的孩子节点连接即可;若节点 T T T既有左孩子,也有右孩子,则需要从 T T T的左右子树中找到一个节点 R R R来弥补 T T T在树中的位置,即将 R R R替换 T T T,并且从原本 T T T的左右子树中删除掉 R R R,这个节点 R R R需要它的值比 T T T的左子树中所有值都大,又要比 T T T的右子树的所有值都小,故这个节点 R R R可以是 T T T的左子树中的最大值的节点,也可以是 T T T的右子树中最小值的节点。

代码

# -*- coding: utf-8 -*-
"""
Created on Mon Apr  8 20:16:42 2019

@author: Administrator
"""

class BinaryTree(object):
    def __init__(self,data):
        self.data=data
        self.lchild=None
        self.rchild=None
        self.forth=None

        
    
class BinarySearchTree(object):
    def __init__(self,root=None):
        self.root=root
        self.size=0
        self.head=BinaryTree(None)       #为根节点额外创建一个头节点
        self.root.forth=self.head
        self.head.lchild=self.root
        
            
    def FindMin(self,node):              #寻找以node为根的二叉排序树的最小值所在节点
        if node:
            current=node
            while current.lchild:
                current=current.lchild
            return current
        else:
            return None
    def FindMax(self,node):              #寻找以node为根的二叉排序树的最大值所在节点
        if node:
            current=node
            while current.rchild:
                current=current.rchild
            return current
        else:
            return None


    #查找操作,返回查找结果与节点
    def _SearchBST(self,key,T):
        if not T:
            return False,T
        else:
            if key==T.data:
                return True,T
            elif key<T.data:
                return self._SearchBST(key,T.lchild)
            else:
                return self._SearchBST(key,T.rchild)
    def SearchBST(self,key):
        if self.root:
            result,location=self._SearchBST(key,self.root)
            if result:
                print('查找成功')
                return location
            else:
                print('查找失败')
        else:
            print('空表,查找失败')
    
    #插入操作,需要先判断插入值是否已经存在
    def _InsertBST(self,key):
        node=BinaryTree(key)
        if not self.root:
            self.root=node
            self.size+=1
        else:
            current=self.root
            while True:
                if key<current.data:
                    if current.lchild:
                        current=current.lchild
                    else:
                        current.lchild=node
                        node.forth=current
                        self.size+=1
                        break
                elif key>current.data:
                    if current.rchild:
                        current=current.rchild
                    else:
                        current.rchild=node
                        node.forth=current
                        self.size+=1
                        break
                else:
                    break
    def InsertBST(self,key):
        result,location=self._SearchBST(key,self.root)
        if result:
            print('查找值在二叉查找树中已存在,返回其节点:')
            return location
        else:
            self._InsertBST(key)
            return True
    
    #删除操作,一共有三种情况:该节点无孩子,有一个孩子,有两个孩子
    def _DeleteBST(self,key,T):
        if T.forth.lchild==T:                    #如果要删除的节点为它双亲节点的左节点
            if T.rchild and T.lchild:            #T有两个孩子
                node=self.FindMin(T.rchild)
                self._DeleteBST(node.data,node)
                node.lchild=T.lchild
                node.rchild=T.rchild
                node.forth=T.forth
            elif T.lchild and not T.rchild:      #T只有一个孩子
                T.lchild.forth=T.forth
                T.forth.lchild=T.lchild
            elif not T.lchild and T.rchild:
                T.rchild.forth=T.forth
                T.forth.lchild=T.rchild
            else:
                T.forth.lchild=None              #T没有孩子
        else:                                    #如果要删除的节点为它双亲节点的右节点
            if T.rchild and T.lchild:
                node=self.FindMin(T.rchild)
                self._DeleteBST(node.data,node)
                node.lchild=T.lchild
                node.rchild=T.rchild
                node.forth=T.forth
            elif T.lchild and not T.rchild:
                T.lchild.forth=T.forth
                T.forth.rchild=T.lchild
            elif not T.lchild and T.rchild:
                T.rchild.forth=T.forth
                T.forth.rchild=T.rchild
            else:
                T.forth.rchild=None
    def DeleteBST(self,key):
        result,T=self._SearchBST(key,self.root)
        if not result:
            print('删除值在原表中不存在,删除失败')
        else:
            self._DeleteBST(key,T)
            self.root=self.head.lchild
            return True


平衡二叉树(AVL树)

定义平衡二叉树 ( S e l f − B a l a n c i n g   B i n a r y   S e a r c h   T r e e   或   H e i g h t − B a l a n c e d   B i n a r y   S e a r c h   T r e e ) (Self-Balancing\ Binary\ Search\ Tree\ 或\ Height-Balanced\ Binary\ Search\ Tree) (SelfBalancing Binary Search Tree  HeightBalanced Binary Search Tree),是一种二叉排序树,其中每一个节点的左子树和右子树的高度差的绝对值至多等于1 。
平衡因子:将二叉树上结点的左子树高度减去右子树高度的值称为平衡因子 B F ( B a l a n c e   F a c t o r ) BF(Balance\ Factor) BF(Balance Factor)
最小不平衡子树:距离插入结点最近的,且平衡因子的绝对值大于1的结点 T T T,以 T T T为根的子树,我们称为最小不平衡子树。

实现基本原理

插入操作实现原理:平衡二叉树构建的基本思想就是在构建二叉排序树的过程中,每当插入一个结点时,先检查是否因插入而破坏了树的平衡性,若是,则找出最小不平衡子树。在保持二叉排序树特性的前提下,调整最小不平衡子树中各结点之间的链接关系,进行相应的旋转,使之成为新的平衡子树。在代码实现过程中,需要注意的细节有两处,一个是关于旋转方式,另一个则是旋转后节点的高度的变动。
 则插入节点从而破坏平衡性的情况有如此四种:(设最小不平衡子树的根节点为 P P P)
情况1.对 P P P的左孩子的左子树进行一次插入,此时只需对整个最小不平衡子树进行一此右旋转即可。
情况1
情况2.对 P P P的左孩子的右子树进行一次插入,此时需要先对以 C C C为根的子树进行左旋转,再对局部旋转后得到的以P为根的子树进行右旋转。
情况2
情况3.对 P P P的右孩子的左子树进行一次插入,此时需要先对以 C C C为根的子树进行右旋转,再对局部旋转后得到的以P为根的子树进行左旋转。

情况3
情况4.对 P P P的右孩子的右子树进行一次插入,此时只需对以 P P P为根的子树进行左旋转即可。
情况4
删除操作的实现原理
 节点的删除有以下四种情况:
情况1.当前节点为要删除的节点且是树叶(无子树),直接删除,当前节点(为None)的平衡不受影响。
情况2.当前节点为要删除的节点且只有一个左孩子或右孩子,用左孩子或右孩子代替当前节点,当前节点的平衡不受影响。
情况3.当前节点为要删除的节点且有左子树与右子树:如果右子树高度较高,则从右子树选取最小节点,将其值赋予当前节点,然后删除右子树的最小节点。如果左子树高度较高,则从左子树选取最大节点,将其值赋予当前节点,然后删除左子树的最大节点。这样操作当前节点的平衡不会被破坏。
情况4.当前节点不是要删除的节点,则对其左子树或者右子树进行递归操作。当前节点的平衡条件可能会被破坏,需要进行平衡操作。进行平衡操作也有四种情况,和插入操作时的四种情况相同。

代码

节点:

class BinaryTree(object):
    def __init__(self,data):
        self.data=data
        self.lchild=None
        self.rchild=None
        self.height=0

AVL_Tree:成员:

class AVL_Tree(object):
    def __init__(self):
        self.root=None

AVL_Tree:节点高度获取方法:

def get_Height(self,T):#获取节点高度
    if not T:
    #用于计算T的祖先的高度,方便在删除T后,其祖先的高度进行-1操作时方便
        return -1      
    else:
        return T.height

AVL_Tree:树的旋转(注意关于节点的高度的赋值):

def _R_single_Rotate(self,T):           #右旋转
    L=T.lchild
    T.lchild=L.rchild
    L.rchild=T
    T.height=max(self.get_Height(T.lchild),self.get_Height(T.lchild))+1
    L.height=max(self.get_Height(L.lchild),self.get_Height(L.lchild))+1
    return L
    
def _L_single_Rotate(self,T):           #左旋转
    L=T.rchild
    T.rchild=L.lchild
    L.lchild=T
    T.height=max(self.get_Height(T.lchild),self.get_Height(T.lchild))+1
    L.height=max(self.get_Height(L.lchild),self.get_Height(L.lchild))+1
    return L
    
def _R_double_Rotate(self,T):           #先对T的左孩子进行左旋转,再对T进行右旋转
    T.lchild=self._L_single_Rotate(T.lchild)
    return self._R_single_Rotate(T)
        
def _L_double_Rotate(self,T):           #先对T的右孩子进行右旋转,再对T进行左旋转
    T.rchild=self._R_single_Rotate(T.rchild)
    return self._L_single_Rotate(T)

AVL_Tree:插入方法:

    def _Insert_AVL(self,key,T):
        if not T:
            T=BinaryTree(key)
        else:
            if key<T.data:
                T.lchild=self._Insert_AVL(key,T.lchild)
                if self.get_Height(T.lchild)-self.get_Height(T.rchild)==2:
                    if key<T.lchild.data:
                        T=self._R_single_Rotate(T)
                    else:
                        T=self._R_double_Rotate(T)
            elif key>T.data:
                T.rchild=self._Insert_AVL(key,T.rchild)
                if self.get_Height(T.rchild)-self.get_Height(T.lchild)==2:
                    if key<T.rchild.data:
                        T=self._L_double_Rotate(T)
                    else:
                        T=self._L_single_Rotate(T)
            else:
                raise KeyError('Error,key in tree!')
        T.height=max(self.get_Height(T.lchild),self.get_Height(T.rchild))+1
        #因为虽然在插入操作中,进行旋转时对变动的节点高度进行了重新赋值,
        #但是对于那些节点的祖先,并没有对其高度重新赋值,在旋转过后,
        #其祖先节点的高度可能会发生变化。
        
        return T
    
    def Insert_AVL(self,key):
        if self.root:
            self.root=self._Insert_AVL(key,self.root)
        else:
            self.root=BinaryTree(key)

AVL_Tree:删除方法:

def _get_Min(self,T):                   #寻找节点T所对应子树的最小值节点
    if T:
        if T.lchild:
            return self._get_Min(T.lchild)
        else:
            return T
    else:
        return None
        
def _get_Max(self,T):                #寻找节点T所对应子树的最大值节点
    if T:
        if T.rchild:
            return self._get_Max(T.rchild)
        else:
            return T
    else:
        return None

def _Delete_AVL(self,key,T):
    if T is None:
        raise KeyError('Error,key not in tree')
    elif key<T.data:
        T.lchild=self._Delete_AVL(key,T.lchild)
        if self.get_Height(T.rchild)-self.get_Height(T.lchild)==2:
            if self.get_Height(T.rchild.rchild)>=self.get_Height(T.rchild.lchild):
                T=self._L_single_Rotate(T)
            else:
                T=self._L_double_Rotate(T)
    elif key>T.data:
        T.rchild=self._Delete_AVL(key,T.rchild)
        if self.get_Height(T.lchild)-self.get_Height(T.rchild)==2:
            if self.get_Height(T.lchild.lchild)>=self.get_Height(T.lchild.rchild):
                T=self._R_single_Rotate(T)
            else:
                T=self._R_double_Rotate
    elif T.lchild and T.rchild:
        if self.get_Height(T.lchild)>=self.get_Height(T.rchild):
            node=self._get_Max(T.lchild)
            T.data=node.data
            T.lchild=self._Delete_AVL(node.data,T.lchild)
        else:
            node=self._get_Min(T.rchild)
            T.data=node.data
            T.rchild=self._get_Min(node.data,T.rchild)
    else:
        if T.rchild:
            T=T.rchild
        else:
            T=T.lchild

    if T:
        T.height=max(self.get_Height(T.lchild),self.get_Height(T.rchild))+1
            
        return T
        
def Delete_AVL(self,key):
    self.root=self._Delete_AVL(key,self.root)

AVL_Tree:查找方法:

def _Search_AVL(self,key,T):
    if T:
        if key<T.data:
            return self._Search_AVL(key,T.lchild)
        elif key>T.data:
            return self._Search_AVL(key,T.rchild)
        else:
            return T
    else:
        raise KeyError('key not in tree')
def Search_AVL(self,key):
    return self._Search_AVL(key,self.root)			 #返回查找到的节点

完整代码

# -*- coding: utf-8 -*-
"""
Created on Tue Apr  9 16:11:47 2019

@author: Administrator
"""

class BinaryTree(object):
    def __init__(self,data):
        self.data=data
        self.lchild=None
        self.rchild=None
        self.height=0
   
class AVL_Tree(object):
    def __init__(self):
        self.root=None
    
    def get_Height(self,T):            #获取节点高度,如果节点为None,则高度为-1,此举方便对节点的高度进行计算
        if not T:
            return -1                     #用于计算node的祖先的高度,方便在删除node后,其祖先的高度进行-1操作时方便
        else:
            return T.height
        
    def _R_single_Rotate(self,T):                 #右旋转
        L=T.lchild
        T.lchild=L.rchild
        L.rchild=T
        T.height=max(self.get_Height(T.lchild),self.get_Height(T.lchild))+1
        L.height=max(self.get_Height(L.lchild),self.get_Height(L.lchild))+1
        return L

    def _L_single_Rotate(self,T):                 #左旋转
        L=T.rchild
        T.rchild=L.lchild
        L.lchild=T
        T.height=max(self.get_Height(T.lchild),self.get_Height(T.lchild))+1
        L.height=max(self.get_Height(L.lchild),self.get_Height(L.lchild))+1
        return L
    
    def _R_double_Rotate(self,T):           #先对T的左孩子进行左旋转,再对T进行右旋转
        T.lchild=self._L_single_Rotate(T.lchild)
        return self._R_single_Rotate(T)
        
    def _L_double_Rotate(self,T):           #先对T的右孩子进行右旋转,再对T进行左旋转
        T.rchild=self._R_single_Rotate(T.rchild)
        return self._L_single_Rotate(T)
        
    def _get_Min(self,T):                   #寻找节点T所对应子树的最小值节点
        if T:
            if T.lchild:
                return self._get_Min(T.lchild)
            else:
                return T
        else:
            return None
        
    def _get_Max(self,T):                #寻找节点T所对应子树的最大值节点
        if T:
            if T.rchild:
                return self._get_Max(T.rchild)
            else:
                return T
        else:
            return None
    
    def _Search_AVL(self,key,T):
        if T:
            if key<T.data:
                return self._Search_AVL(key,T.lchild)
            elif key>T.data:
                return self._Search_AVL(key,T.rchild)
            else:
                return T
        else:
            raise KeyError('key not in tree')
    def Search_AVL(self,key):
        return self._Search_AVL(key,self.root)
    
    def _Insert_AVL(self,key,T):
        if T is None:
            T=BinaryTree(key)
        else:
            if key<T.data:
                T.lchild=self._Insert_AVL(key,T.lchild)
                if self.get_Height(T.lchild)-self.get_Height(T.rchild)==2:
                    if key<T.lchild.data:
                        T=self._R_single_Rotate(T)
                    else:
                        T=self._R_double_Rotate(T)
            elif key>T.data:
                T.rchild=self._Insert_AVL(key,T.rchild)
                if self.get_Height(T.rchild)-self.get_Height(T.lchild)==2:
                    if key<T.rchild.data:
                        T=self._L_double_Rotate(T)
                    else:
                        T=self._L_single_Rotate(T)
            else:
                raise KeyError('Error,key in tree!')
        T.height=max(self.get_Height(T.lchild),self.get_Height(T.rchild))+1
        return T
    
    def Insert_AVL(self,key):
        if self.root:
            self.root=self._Insert_AVL(key,self.root)
        else:
            self.root=BinaryTree(key)

    def _Delete_AVL(self,key,T):
        if T is None:
            raise KeyError('Error,key not in tree')
        elif key<T.data:
            T.lchild=self._Delete_AVL(key,T.lchild)
            if self.get_Height(T.rchild)-self.get_Height(T.lchild)==2:
                if self.get_Height(T.rchild.rchild)>=self.get_Height(T.rchild.lchild):
                    T=self._L_single_Rotate(T)
                else:
                    T=self._L_double_Rotate(T)
        elif key>T.data:
            T.rchild=self._Delete_AVL(key,T.rchild)
            if self.get_Height(T.lchild)-self.get_Height(T.rchild)==2:
                if self.get_Height(T.lchild.lchild)>=self.get_Height(T.lchild.rchild):
                    T=self._R_single_Rotate(T)
                else:
                    T=self._R_double_Rotate
        elif T.lchild and T.rchild:
            if self.get_Height(T.lchild)>=self.get_Height(T.rchild):
                node=self._get_Max(T.lchild)
                T.data=node.data
                T.lchild=self._Delete_AVL(node.data,T.lchild)
            else:
                node=self._get_Min(T.rchild)
                T.data=node.data
                T.rchild=self._get_Min(node.data,T.rchild)
        else:
            if T.rchild:
                T=T.rchild
            else:
                T=T.lchild
        
        if T:
            T.height=max(self.get_Height(T.lchild),self.get_Height(T.rchild))+1
            
        return T
    def Delete_AVL(self,key):
        self.root=self._Delete_AVL(key,self.root)

注释

关于AVL树的的旋转示意图,借鉴于博客园的一位博主:再见紫罗兰的博文,代码方面和他的代码也没有多大的差异。原文链接:
https://www.cnblogs.com/linxiyue/p/3659448.html?utm_source=tuicool&utm_medium=referral

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值