二叉排序树
定义:二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(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)
(Self−Balancing Binary Search Tree 或 Height−Balanced 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的左孩子的左子树进行一次插入,此时只需对整个最小不平衡子树进行一此右旋转即可。
情况2.对
P
P
P的左孩子的右子树进行一次插入,此时需要先对以
C
C
C为根的子树进行左旋转,再对局部旋转后得到的以P为根的子树进行右旋转。
情况3.对
P
P
P的右孩子的左子树进行一次插入,此时需要先对以
C
C
C为根的子树进行右旋转,再对局部旋转后得到的以P为根的子树进行左旋转。
情况4.对
P
P
P的右孩子的右子树进行一次插入,此时只需对以
P
P
P为根的子树进行左旋转即可。
删除操作的实现原理:
节点的删除有以下四种情况:
情况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