文档库 最新最全的文档下载
当前位置:文档库 › 平衡二叉树

平衡二叉树

平衡二叉树
平衡二叉树

步一步写平衡二叉树(AVL树)

作者:C小加更新时间:2012-8-20

平衡二叉树(Balanced Binary Tree)是二叉查找树的一个进化体,也是第一个引入平衡概念的二叉树。1962年,G.M. Adelson-Velsky 和 E.M. Landis发明了这棵树,所以它又叫AVL树。平衡二叉树要求对于每一个节点来说,它的左右子树的高度之差不能超过1,如果插入或者删除一个节点使得高度之差大于1,就要进行节点之间的旋转,将二叉树重新维持在一个平衡状态。这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。

平衡二叉树实现的大部分过程和二叉查找树是一样的(学平衡二叉树之前一定要会二叉查找树),区别就在于插入和删除之后要写一个旋转算法去维持平衡,维持平衡需要借助一个节点高度的属性。我参考了机械工业出版社的《数据结构与算法分析-C语言描述》写了一个C++版的代码。这本书的AVLTree讲的很好,不过没有很完整的去描述。我会一步一步的讲解如何写平衡二叉树,重点是平衡二叉树的核心部分,也就是旋转算法。

第一步:节点信息

相对于二叉查找树的节点来说,我们需要用一个属性二叉树的高度,目的是维护插入和删除过程中的旋转算法。

代码如下:

//AVL树节点信息

template

class TreeNode

{

public:

TreeNode():lson(NULL),rson(NULL),freq(1),hgt(0){}

T data;//值

int hgt;//以此节点为根的树的高度

unsigned int freq;//频率

TreeNode* lson;//指向左儿子的地址

TreeNode* rson;//指向右儿子的地址

};

第二步:平衡二叉树类的声明

声明中的旋转函数将在后边的步骤中详解。

代码如下:

//AVL树类的属性和方法声明

template

class AVLTree

{

private:

TreeNode* root;//根节点

void insertpri(TreeNode* &node,T x);//插入

TreeNode* findpri(TreeNode* node,T x);//查找

void insubtree(TreeNode* node);//中序遍历

void Deletepri(TreeNode* &node,T x);//删除

int height(TreeNode* node);//求树的高度

void SingRotateLeft(TreeNode* &k2);//左左情况下的旋转

void SingRotateRight(TreeNode* &k2);//右右情况下的旋转

void DoubleRotateLR(TreeNode* &k3);//左右情况下的旋转

void DoubleRotateRL(TreeNode* &k3);//右左情况下的旋转

int Max(int cmpa,int cmpb);//求最大值

public:

AVLTree():root(NULL){}

void insert(T x);//插入接口

TreeNode* find(T x);//查找接口

void Delete(T x);//删除接口

void traversal();//遍历接口

};

第三步:两个辅助方法

旋转算法需要借助于两个功能的辅助,一个是求树的高度,一个是求两个高度的最大值。这里规定,一棵空树的高度为-1,只有一个根节点的树的高度为0,以后每多一层高度加1。为了解决指针NULL这种情况,写了一个求高度的函数,这个函数还是很有必要的。

代码如下:

//计算以节点为根的树的高度

template

int AVLTree::height(TreeNode* node)

{

if(node!=NULL)

return node->hgt;

return -1;

}

//求最大值

template

int AVLTree::Max(int cmpa,int cmpb)

{

return cmpa>cmpb?cmpa:cmpb;

}

第四步:旋转

对于一个平衡的节点,由于任意节点最多有两个儿子,因此高度不平衡时,此节点的两颗子树的高度差2.容易看出,这种不平衡出现在下面四种情况:

1、6节点的左子树3节点高度比右子树7节点大2,左子树3节点的左子树1节点高度大于右子树4节点,这种情况成为左左。

2、6节点的左子树2节点高度比右子树7节点大2,左子树2节点的左子树1节点高度小于右子树4节点,这种情况成为左右。

3、2节点的左子树1节点高度比右子树5节点小2,右子树5节点的左子树3节点高度大于右子树6节点,这种情况成为右左。

4、2节点的左子树1节点高度比右子树4节点小2,右子树4节点的左子树3节点高度小于右子树6节点,这种情况成为右右。

从图2中可以可以看出,1和4两种情况是对称的,这两种情况的旋转算法是一致的,只需要经过一次旋转就可以达到目标,我们称之为单旋转。2和3两种情况也是对称的,这两种情况的旋转算法也是一致的,需要进行两次旋转,我们称之为双旋转。

第五步:单旋转

单旋转是针对于左左和右右这两种情况的解决方案,这两种情况是对称的,只要解决了左左这种情况,右右就很好办了。图3是左左情况的解决方案,节点k2不满足平衡特性,因为它的左子树k1比右子树Z深2层,而且k1子树中,更深的一层的是k1的左子树X子树,所以属于左左情况。

为使树恢复平衡,我们把k2变成这棵树的根节点,因为k2大于k1,把k2置于k1的右子树上,而原本在k1右子树的Y大于k1,小于k2,就把Y置于k2的左子树上,这样既满足了二叉查找树的性质,又满足了平衡二叉树的性质。

这样的操作只需要一部分指针改变,结果我们得到另外一颗二叉查找树,它是一棵AVL树,因为X向上一移动了一层,Y还停留在原来的层面上,Z向下移动了一层。整棵树的新高度和之前没有在左子树上插入的高度相同,插入操作使得X高度长高了。因此,由于这颗子树高度没有变化,所以通往根节点的路径就不需要继续旋转了。

代码如下:

//左左情况下的旋转

template

void AVLTree::SingRotateLeft(TreeNode* &k2)

{

TreeNode* k1;

k1=k2->lson;

k2->lson=k1->rson;

k1->rson=k2;

k2->hgt=Max(height(k2->lson),height(k2->rson))+1;

k1->hgt=Max(height(k1->lson),k2->hgt)+1;

}

//右右情况下的旋转

template

void AVLTree::SingRotateRight(TreeNode* &k2)

{

TreeNode* k1;

k1=k2->rson;

k2->rson=k1->lson;

k1->lson=k2;

k2->hgt=Max(height(k2->lson),height(k2->rson))+1;

k1->hgt=Max(height(k1->rson),k2->hgt)+1;

}

第六步:双旋转

对于左右和右左这两种情况,单旋转不能使它达到一个平衡状态,要经过两次旋转。双旋转是针对于这两种情况的解决方案,同样的,这样两种情况也是对称的,只要解决了左右这种情况,右左就很好办了。图4是左右情况的解决方案,节点k3不满足平衡特性,因为它的左子树k1比右子树Z深2层,而且k1子树中,更深的一层的是k1的右子树k2子树,所以属于左右情况。

为使树恢复平衡,我们需要进行两步,第一步,把k1作为根,进行一次右右旋转,旋转之后就变成了左左情况,所以第二步再进行一次左左旋转,最后得到了一棵以k2为根的平衡二叉树树。

代码如下:

//左右情况的旋转

template

void AVLTree::DoubleRotateLR(TreeNode* &k3)

{

SingRotateRight(k3->lson);

SingRotateLeft(k3);

}

//右左情况的旋转

template

void AVLTree::DoubleRotateRL(TreeNode* &k3)

{

SingRotateLeft(k3->rson);

SingRotateRight(k3);

}

第七步:插入

插入的方法和二叉查找树基本一样,区别是,插入完成后需要从插入的节点开始维护一个到根节点的路径,每经过一个节点都要维持树的平衡。维持树的平衡要根据高度差的特点选择不同的旋转算法。

代码如下:

//插入

template

void AVLTree::insertpri(TreeNode* &node,T x)

{

if(node==NULL)//如果节点为空,就在此节点处加入x信息

{

node=new TreeNode();

node->data=x;

return;

}

if(node->data>x)//如果x小于节点的值,就继续在节点的左子树中插入x

{

insertpri(node->lson,x);

if(2==height(node->lson)-height(node->rson))

if(xlson->data)

SingRotateLeft(node);

else

DoubleRotateLR(node);

}

else if(node->data

{

insertpri(node->rson,x);

if(2==height(node->rson)-height(node->lson))//如果高度之差为2的话就失去了平衡,需要旋转

if(x>node->rson->data)

SingRotateRight(node);

else

DoubleRotateRL(node);

}

else ++(node->freq);//如果相等,就把频率加1

node->hgt=Max(height(node->lson),height(node->rson));

}

//插入接口

template

void AVLTree::insert(T x)

insertpri(root,x);

}

第八步:查找

和二叉查找树相比,查找方法没有变法,不过根据存储的特性,AVL树能维持在一个O(logN)的稳定的时间,而二叉查找树则相当不稳定。

代码如下:

//查找

template

TreeNode* AVLTree::findpri(TreeNode* node,T x)

{

if(node==NULL)//如果节点为空说明没找到,返回NULL

{

return NULL;

}

if(node->data>x)//如果x小于节点的值,就继续在节点的左子树中查找x

{

return findpri(node->lson,x);

}

else if(node->data

{

return findpri(node->rson,x);

}

else return node;//如果相等,就找到了此节点

}

//查找接口

template

TreeNode* AVLTree::find(T x)

{

return findpri(root,x);

}

第九步:删除

删除的方法也和二叉查找树的一致,区别是,删除完成后,需要从删除节点的父亲开始向上维护树的平衡一直到根节点。

代码如下:

//删除

template

void AVLTree::Deletepri(TreeNode* &node,T x)

{

if(node==NULL) return ;//没有找到值是x的节点

if(x < node->data)

Deletepri(node->lson,x);//如果x小于节点的值,就继续在节点的左子树中删除x if(2==height(node->rson)-height(node->lson))

if(node->rson->lson!=NULL&&(height(node->rson->lson)>height(node-> rson->rson)) )

DoubleRotateRL(node);

else

SingRotateRight(node);

}

else if(x > node->data)

{

Deletepri(node->rson,x);//如果x大于节点的值,就继续在节点的右子树中删除x if(2==height(node->lson)-height(node->rson))

if(node->lson->rson!=NULL&& (height(node->lson->rson)>height(node-> lson->lson) ))

DoubleRotateLR(node);

else

SingRotateLeft(node);

}

else//如果相等,此节点就是要删除的节点

{

if(node->lson&&node->rson)//此节点有两个儿子

{

TreeNode* temp=node->rson;//temp指向节点的右儿子

while(temp->lson!=NULL) temp=temp->lson;//找到右子树中值最小的节点

//把右子树中最小节点的值赋值给本节点

node->data=temp->data;

node->freq=temp->freq;

Deletepri(node->rson,temp->data);//删除右子树中最小值的节点

if(2==height(node->lson)-height(node->rson))

{

if(node->lson->rson!=NULL&& (height(node->lson->rson)>height(no de->lson->lson) ))

DoubleRotateLR(node);

else

SingRotateLeft(node);

}

}

else//此节点有1个或0个儿子

{

TreeNode* temp=node;

if(node->lson==NULL)//有右儿子或者没有儿子

node=node->rson;

else if(node->rson==NULL)//有左儿子

node=node->lson;

delete(temp);

temp=NULL;

}

}

if(node==NULL) return;

node->hgt=Max(height(node->lson),height(node->rson))+1;

return;

}

//删除接口

template

void AVLTree::Delete(T x)

{

Deletepri(root,x);

}

第十步:中序遍历

代码如下:

//中序遍历函数

template

void AVLTree::insubtree(TreeNode* node)

{

if(node==NULL) return;

insubtree(node->lson);//先遍历左子树

cout<data<<" ";//输出根节点

insubtree(node->rson);//再遍历右子树

}

//中序遍历接口

template

void AVLTree::traversal()

{

insubtree(root);

}

第十一步:关于效率

此数据结构插入、查找和删除的时间复杂度均为O(logN),但是插入和删除需要额外的旋转算法需要的时间,有时旋转过多也会影响效率。

关于递归和非递归。我用的是递归的方法进行插入,查找和删除,而非递归的方法一般来说要比递归的方法快很多,但是我感觉非递归的方法写出来会比较困难,所以我还是选择了递归的方法。

还有一种效率的问题是关于高度信息的存储,由于我们需要的仅仅是高度的差,不需要知道这棵树的高度,所以只需要使用两个二进制位就可以表示这个差。这样可以避免平衡因子的重复计算,可以稍微的加快一些速度,不过代码也丧失了相对简明性和清晰度。如果采用递归写法的话,这种微加速就更显得微乎其微了。

如果有哪些不对的或者不清晰的地方请指出,我会修改并加以完善。

附:完整代码

平衡二叉树的生成过程

二叉排序树变成平衡二叉树 对于二叉查找树,尽管查找、插入及删除操作的平均运行时间为O(logn),但是它们的最差运行时间都是O(n),原因在于对树的形状没有限制。 平衡二叉树又称为AVL树,它或者是一棵空树,或者是有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左右子树的深度之差的绝对值不超过1。二叉树的的平衡因子BF为:该结点的左子树的深度减去它的右子树的深度,则平衡二叉树的所有结点的平衡因子为只可能是:-1、0和1 一棵好的平衡二叉树的特征: (1)保证有n个结点的树的高度为O(logn) (2)容易维护,也就是说,在做数据项的插入或删除操作时,为平衡树所做的一些辅助操作时间开销为O(1) 一、平衡二叉树的构造 在一棵二叉查找树中插入结点后,调整其为平衡二叉树。若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性。首先要找出插入新结点后失去平衡的最小子树根结点的指针。然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树。当失去平衡的最小子树被调整为平衡子树后,原有其他所有不平衡子树无需调整,整个二叉排序树就又成为一棵平衡二叉树 1.调整方法 (1)插入点位置必须满足二叉查找树的性质,即任意一棵子树的左结点都小于根结点,右结点大于根结点 (2)找出插入结点后不平衡的最小二叉树进行调整,如果是整个树不平衡,才进行整个树的调整。 2.调整方式 (1)LL型 LL型:插入位置为左子树的左结点,进行向右旋转(LL表示的是在做子树的左结点进行插入) 由于在A的左孩子B的左子树上插入结点F,使A的平衡因子由1变为2,成为不平衡的最小二叉树根结点。此时A结点顺时针右旋转,旋转过程中遵循“旋转优先”的规则,A结点替换D结点成为B结点的右子树,D结点成为A结点的左孩子。 (2)RR型

数据结构程序报告(平衡二叉树的操作)

计算机科学学院数据结构课程设计报告 平衡二叉树操作 学生姓名: 学号: 班级: 指导老师: 报告日期:

1.需求分析 1.建立平衡二叉树并进行创建、查找、插入、删除等功能。 2.设计一个实现平衡二叉树的程序,可进行创建、查找、插入、删除等操作,实现动态的输入数据,实时的输出该树结构。 3.测试数据:自选数据 2.概要设计 1.抽象数据类型定义: typedef struct BSTNode { int data; int bf; //节点的平衡因子 struct BSTNode *lchild,*rchild; //左右孩子指针 }BSTNode,*BSTree; void CreatBST(BSTree &T); //创建平衡二叉树 void R_Rotate(BSTree &p); //对以*p为根的二叉排序树作左旋处理 void L_Rotate(BSTree &p); //对以*p为根的二叉排序树作左旋处理 void LeftBalance(BSTree &T); //对以指针T所指结点为根的二叉树作左平衡旋转处理void RightBalance(BSTree &T); //对以指针T所指结点为根的二叉树作右平衡旋转处理bool InsertAVL(BSTree &T,int e,bool &taller); //插入结点e bool SearchBST(BSTree &T,int key); //查找元素key是否在树T中 void LeftBalance_div(BSTree &p,int &shorter); //删除结点时左平衡旋转处理 void RightBalance_div(BSTree &p,int &shorter); //删除结点时右平衡旋转处理 void Delete(BSTree q,BSTree &r,int &shorter); //删除结点 int DeleteA VL(BSTree &p,int x,int &shorter); //平衡二叉树的删除操作 void PrintBST(BSTree T,int m); //按树状打印输出二叉树的元素 2.主程序的流程 3.各模块之间的层次调用

数据结构平衡二叉树的操作演示

平衡二叉树操作的演示 1.需求分析 本程序是利用平衡二叉树,实现动态查找表的基本功能:创建表,查找、插入、删除。具体功能: (1)初始,平衡二叉树为空树,操作界面给出创建、查找、插入、删除、合并、分裂六种操作供选择。每种操作均提示输入关键字。每次插入或删除一个结点后,更 新平衡二叉树的显示。 (2)平衡二叉树的显示采用凹入表现形式。 (3)合并两棵平衡二叉树。 (4)把一棵二叉树分裂为两棵平衡二叉树,使得在一棵树中的所有关键字都小于或等于x,另一棵树中的任一关键字都大于x。 如下图: 2.概要设计 平衡二叉树是在构造二叉排序树的过程中,每当插入一个新结点时,首先检查是否因插入新结点而破坏了二叉排序树的平衡性,若是则找出其中的最小不平衡子树,在保持二叉排序树特性的前提下,调整最小不平衡子树中各结点之间的链接关系,进行相应的旋转,使之成为新的平衡子树。

具体步骤: (1)每当插入一个新结点,从该结点开始向上计算各结点的平衡因子,即计算该结点的祖先结点的平衡因子,若该结点的祖先结点的平衡因子的绝对值不超过1,则平衡二叉树没有失去平衡,继续插入结点; (2)若插入结点的某祖先结点的平衡因子的绝对值大于1,则找出其中最小不平衡子树的根结点; (3)判断新插入的结点与最小不平衡子树的根结点个关系,确定是那种类型的调整;(4)如果是LL型或RR型,只需应用扁担原理旋转一次,在旋转过程中,如果出现冲突,应用旋转优先原则调整冲突;如果是LR型或RL型,则需应用扁担原理旋转两次,第一次最小不平衡子树的根结点先不动,调整插入结点所在子树,第二次再调整最小不平衡子树,在旋转过程中,如果出现冲突,应用旋转优先原则调整冲突;(5)计算调整后的平衡二叉树中各结点的平衡因子,检验是否因为旋转而破坏其他结点的平衡因子,以及调整后平衡二叉树中是否存在平衡因子大于1的结点。 流程图 3.详细设计 二叉树类型定义: typedef int Status; typedef int ElemType; typedef struct BSTNode{

平衡二叉树(AVL)的查找、插入和删除

平衡二叉树(AVL)查找、插入和删除 小组成员: 陈静101070009 陈丹璐101070006 陈娇101070008

目录 平衡二叉树(AVL) (1) 查找、插入和删除 (1) 问题描述 (2) 设计说明 (3) (一)ADT (3) (二)算法思想 (5) (三)数据结构 (12) (四)程序结构与流程 (13) 运行平台及开发工具 (15) I/O格式 (15) 算法复杂度分析 (18) 源代码 (18) 小结 (37) 问题描述 利用平衡二叉树实现一个动态查找表。

(1)实现动态查找表的三种基本功能:查找、插入和删除。 (2)初始时,平衡二叉树为空树,操作界面给出创建、查找、插入和删除和退出五种操作供选择。每种操作均要提示输入关键字。创建时,根据提示输入数据,以-1为输入数据的结束标志,若输入数据重复,则给出已存在相同关键字的提示,并不将其插入到二叉树中。在查找时,如果查找的关键字不存在,则显示不存在查找的关键字,若存在则显示存在要查找的关键字。插入时首先检验原二叉树中是否已存在相同第3 页共38 页- 3 -的关键字,若没有则进行插入并输出二叉树,若有则给出已有相同关键字的提醒。删除时首先检验原二叉树中是否存在要删除的关键字,若有则进行删除后并输出二叉树,若没有则给出不存在要删除的关键字的提醒。 (3)平衡二叉树的显示采用中序遍历的方法输出,还可以根据输出数据是否有序验证对平衡二叉树的操作是否正确。 设计说明 (一)ADT ADT BalancedBinaryTree{ 数据对象D:D是具有相同特性的数据元素的集合。各个数据元素均含有类型相同,可唯一标志的数据元素的关键字。 数据关系R:数据元素同属一个集合。 基本操作P: void R_Rotate(BSTree &p); 初始条件:二叉树存在,且关键字插入到以*p为根的二叉树的左子树的左孩子上; 操作结果:对以*p为根的二叉排序树作右旋处理

平衡二叉树操作演示

数据结构实习报告 题目:平衡二叉树的操作演示 班级:信息管理与信息系统11-1 姓名:崔佳 学号:201101050903 完成日期:2013.06.25

一、需求分析 1. 初始,平衡二叉树为空树,操作界面给出两棵平衡二叉树的显示、查找、插入、删除、销毁、合并两棵树,几种选择。其中查找、插入和删除操作均要提示用户输入关键字。每次插入或删除一个节点后都会更新平衡二叉树的显示。 2. 平衡二叉树的显示采用凹入表形式。 3.每次操作完毕后都会给出相应的操作结果,并进入下一次操作,知道用户选择退出 二、概要设计 1.平衡二叉树的抽象数据类型定义: ADT BalancedBinaryTree{ 数据对象D:D是具有相同特性的数据元素的集合。各个数据元素均含有类型相同,可唯一标志的数据元素的关键字。 数据关系R:数据元素同属一个集合。 基本操作P: InitAVL(BSTree& T) 操作结果:构造一个空的平衡二叉树T DestroyAVL(BSTree& T) 初始条件:平衡二叉树T存在 操作结果:销毁平衡二叉树T SearchAVL(BSTree T,int key) 初始条件:平衡二叉树T存在,key为和关键字相同类型的给定值 操作结果:若T中存在关键字和key相等的数据元素,则返回指向该元素的 指针,否则为空 InsertAVL(BSTree& T,int key,Status& taller) 初始条件:平衡二叉树T存在,key和关键字的类型相同 操作结果:若T中存在关键字等于key的数据元素则返回,若不存在则插入 一个关键字为key的元素 DeleteAVL(BSTree& T,int &key,Status& lower) 初始条件:平衡二叉树T存在,key和关键字的类型相同 操作结果:若T中存在关键字和key相同的数据元素则删除它}ADT BalancedBinaryTree

平衡二叉树 构造方法(绝妙)

平衡二叉树构造方法 平衡二叉树 对于二叉查找树,尽管查找、插入及删除操作的平均运行时间为O(logn),但是它们的最差运行时间都是O(n),原因在于对树的形状没有限制。 平衡二叉树又称为AVL树,它或者是一棵空树,或者是有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左右子树的深度之差的绝对值不超过1。二叉树的的平衡因子BF为:该结点的左子树的深度减去它的右子树的深度,则平衡二叉树的所有结点的平衡因子为只可能是:-1、0和1 一棵好的平衡二叉树的特征: (1)保证有n个结点的树的高度为O(logn) (2)容易维护,也就是说,在做数据项的插入或删除操作时,为平衡树所做的一些辅助操作时间开销为O(1) 一、平衡二叉树的构造 在一棵二叉查找树中插入结点后,调整其为平衡二叉树。若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性。首先要找出插入新结点后失去平衡的最小子树根结点的指针。然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树。当失去平衡的最小子树被调整为平衡子树后,原有其他所有不平衡子树无需调整,整个二叉排序树就又成为一棵平衡二叉树 1.调整方法 (1)插入点位置必须满足二叉查找树的性质,即任意一棵子树的左结点都小于根结点,右结点大于根结点 (2)找出插入结点后不平衡的最小二叉树进行调整,如果是整个树不平衡,才进行整个树的调整。 2.调整方式 (1)LL型 LL型:插入位置为左子树的左结点,进行向右旋转

由于在A的左孩子B的左子树上插入结点F,使A的平衡因子由1变为2,成为不平衡的最小二叉树根结点。此时A结点顺时针右旋转,旋转过程中遵循“旋转优先”的规则,A结点替换D结点成为B结点的右子树,D结点成为A结点的左孩子。 (2)RR型 RR型:插入位置为右子树的右孩子,进行向左旋转 由于在A的右子树C的右子树插入了结点F,A的平衡因子由-1变为-2,成为不平衡的最小二叉树根结点。此时,A结点逆时针左旋转,遵循“旋转优先”的规则,A结点替换D结点成为C的左子树,D结点成为A的右子树。 (3)LR型 LR型:插入位置为左子树的右孩子,要进行两次旋转,先左旋转,再右旋转;第一次最小不平衡子树的根结点先不动,调整插入结点所在的子树,第二次再调整最小不平衡子树。 由于在A的左子树B的右子树上插入了结点F,A的平衡因子由1变为了2,成为不平衡的最小二叉树根结点。第一次旋转A结点不动,先将B的右子树的根结点D向左上旋转提升到B结点的位置,然后再把该D结点向右上旋转提升到A结点的位置。 (4)RL型 RL型:插入位置为右子树的左孩子,进行两次调整,先右旋转再左旋转;处理情况与LR 类似。

数据结构程序报告(平衡二叉树的操作)

数据结构程序报告(平衡二叉树的操作)

计算机科学学院数据结构课程设计报告 平衡二叉树操作 学生姓名: 学号: 班级: 指导老师: 报告日期:

1.需求分析 1.建立平衡二叉树并进行创建、查找、插入、删除等功能。 2.设计一个实现平衡二叉树的程序,可进行创建、查找、插入、删除等操作,实现动态的输入数据,实时的输出该树结构。 3.测试数据:自选数据 2.概要设计 1.抽象数据类型定义: typedef struct BSTNode { int data; int bf; //节点的平衡因子 struct BSTNode *lchild,*rchild; //左右孩子指针 }BSTNode,*BSTree; void CreatBST(BSTree &T); //创建平衡二叉树 void R_Rotate(BSTree &p); //对以*p 为根的二叉排序树作左旋处理 void L_Rotate(BSTree &p); //对以*p 为根的二叉排序树作左旋处理 void LeftBalance(BSTree &T); //对以指针T所指结点为根的二叉树作左平衡旋转处理void RightBalance(BSTree &T); //对以指针T所指结点为根的二叉树作右平衡旋转处理bool InsertA VL(BSTree &T,int e,bool &taller);

//插入结点e bool SearchBST(BSTree &T,int key); //查找元素key是否在树T中 void LeftBalance_div(BSTree &p,int &shorter); void RightBalance_div(BSTree &p,int &shorter);

平衡二叉树-数据结构课程设计论文【可运行测试】

数据结构课程设计 课程名称:平衡二叉树的生成 院系:信息工程学院 年级专业:10级计科 学号: 学生姓名: 指导教师: 开题时间: 2010 年 12 月 01 日 完成时间: 2010 年 12 月 31 日 信息工程学院

X X X X X X X数据结构课程设计成绩评定表 院系:信息工程学院年级专业: 学号:姓名:

摘要 本篇论文系计科专业10年末课程设计论文,按照相应要求写作而成。 主要讨论的是平衡二叉树的生成问题,借助本程序可以由用户输入数值,并生成平衡二叉树,并可以对数据进行方便的修改和删除添加,任意插入或删除一个结点后仍然要求任然构成平衡二叉树,并按中序遍历输出这棵平衡二叉树。· 本论文共由五个章构成,每个内容独立成章,各章下设相应子章节。 各个章节逐渐递进,分别是: 第一章:需求分析 第二章系统设计 第三章编码 第四章测试 第五章维护 本论文特点: 1.论述清楚,目录详尽,可以方便的查询相应章节,方便使用。 2.图文结合,几乎没一个子程序模块都有相应的流程图与之对应,有利于读者理解每 个子程序的设计思路。 3.模块分化清晰,每个模块独立成节,又彼此联系,深化了C语言模块化编程的特点。 4.测试模块配合对应的运行截图,真实可信,对读者理解程序的运行情况起到了很大 作用。 5.程序清单完整详细,解释详细。

目录 第一章需求分析 (1) 1.1功能描述------------------------------------------------1 1.2数据词典------------------------------------------------1 第二章系统设计 (3) 2.1 基本概念介绍----------------------------------------------3 2.2 总体设计--------------------------------------------------8 2.3 插入结点-------------------------------------------------10 2.4 删除结点-------------------------------------------------11 2.5 中序遍历-------------------------------------------------11 第三章编码 (12) 3.1 总体编码------------------------------------------------12 3.2 总流程图------------------------------------------------15 3.3 以指针T所指结点为根的二叉树作右平衡旋转处理------------16 第四章测试 (17) 4.1 创建二叉树测试-------------------------------------------17 4.2 插入结点测试---------------------------------------------19 4.3 删除结点测试---------------------------------------------20 4.4中序遍历结点测试------------------------------------------21 4.5 先序遍历测试---------------------------------------------21 第五章维护 (22) 5.1维护----------------------------------------------------22

二叉排序树与平衡二叉树的实现课程设计

攀枝花学院本科学生课程设计任务书题目二叉排序树与平衡二叉树的实现 1、课程设计的目的 1)使学生进一步理解和掌握课堂上所学各种基本抽象数据类型的逻辑结构、存储结构和操 作实现算法,以及它们在程序中的使用方法。 2)使学生掌握软件设计的基本内容和设计方法,并培养学生进行规范化软件设计的能力。 3)使学生掌握使用各种计算机资料和有关参考资料,提高学生进行程序设计的基本能力。 2、课程设计的内容和要求(包括原始数据、技术要求、工作要求等) 1) (1)以回车('\n')为输入结束标志,输入数列L,生成一棵二叉排序树T; (2)对二叉排序树T作中序遍历,输出结果; (3)计算二叉排序树T查找成功的平均查找长度,输出结果; (4)输入元素x,查找二叉排序树T,若存在含x的结点,则删该结点,并作中序遍历(执行 操作2);否则输出信息“无x”; (5)用数列L,生成平衡的二叉排序树BT:当插入新元素之后,发现当前的二叉排序树BT 不是平衡的二叉排序树,则立即将它转换成新的平衡的二叉排序树BT; (6)计算平衡的二叉排序树BT的平均查找长度,输出结果。 3、主要参考文献 [1]刘大有等,《数据结构》(C语言版),高等教育出版社 [2]严蔚敏等,《数据结构》(C语言版),清华大学出版社 [3]William Ford,William Topp,《Data Structure with C++》清华大学出版社 [4]苏仕华等,数据结构课程设计,机械工业出版社 4、课程设计工作进度计划 第1天完成方案设计与程序框图 第2、3天编写程序代码 第4天程序调试分析和结果 第5天课程设计报告和总结 指导教师(签字)日期年月日 教研室意见: 年月日学生(签字): 接受任务时间:年月日注:任务书由指导教师填写。

平衡二叉树

二叉树: 左子树都小于根节点,右子树都大于根节点。可以动态维护这棵树(因为是树结构,可以有限步完成插入),所以是动态查找算法。时间复杂度为O(logn)在46.5%的情况下,需要把二叉树平衡化成“平衡二叉树”。 平衡二叉树:定义:平衡二叉树或为空树,或为如下性质的二叉排序树: (1)左右子树深度之差的绝对值不超过1; (2)左右子树仍然为平衡二叉树. 平衡因子:平衡因子bf=左子树深度-右子树深度, 每个结点的平衡因子只能是1,0,-1。若其绝对值超过1,则该二叉排序树就是不平衡的。增加一个元素后,平衡二叉树有可能变成不平衡了,所以需要旋转平衡调整。 平衡二叉树算法思想: 若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性。首先要找出插入新结点后失去平衡的最小子树根结点的指针。然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树。当失去平衡的最小子树被调整为平衡子树后,原有其他所有不平衡子树无需调整,整个二叉排序树就又成为一棵平衡二叉树。失去平衡的最小子树是指以离插入结点最近,且平衡因子绝对值大于1的结点作为根的子树。假设用A表示失去平衡的最小子树的根结点,则调整该子树的操作可归纳为下列四种情况:(可以断定插入一个节点一定是在叶子节点上) (1)LL型平衡旋转法 由于在A的左孩子B的左子树上插入结点F,使A的平衡因子由1增至2而失去平衡。故需进行一次顺时针旋转操作。即将A的左孩子B向右上旋转代替A作为根结点,A向右下旋转成为B 的右子树的根结点。而原来B的右子树则变成A的左子树。 (2)RR型平衡旋转法 由于在A的右孩子C 的右子树上插入结点F,使A的平衡因子由-1减至-2而失去平衡。故需进行一次逆时针旋转操作。即将A的右孩子C向左上旋转代替A作为根结点,A向左下旋转成为C 的左子树的根结点。而原来C的左子树则变成A的右子树。

数据结构课程设计-_平衡二叉树操作

课程设计报告 课程名称数据结构课程设计 题目平衡二叉树操作 指导教师 设计起止日 2010-5-16 学院计算机学院 专业软件工程 学生姓名 班级/学号------------ 成绩_________________

一.需求分析 1、建立平衡二叉树并进行创建、增加、删除、调平等操作。 2、设计一个实现平衡二叉树的程序,可进行创建、增加、删除、调平等操作,实现动态的输入数据,实时的输出该树结构。 3、测试数据:自选数据 二.概要设计 平衡二叉树是在构造二叉排序树的过程中,每当插入一个新结点时,首先检查是否因插入新结点而破坏了二叉排序树的平衡性,若是,则找出其中的最小不平衡子树,在保持二叉排序树特性的前提下,调整最小不平衡子树中各结点之间的链接关系,进行相应的旋转,使之成为新的平衡子树。具体步骤如下: ⑴每当插入一个新结点,从该结点开始向上计算各结点的平衡因子,即计算该结点的祖先结点的平衡因子,若该结点的祖先结点的平衡因子的绝对值均不超过1,则平衡二叉树没有失去平衡,继续插入结点; ⑵若插入结点的某祖先结点的平衡因子的绝对值大于1,则找出其中最小不平衡子树的根结点; ⑶判断新插入的结点与最小不平衡子树的根结点的关系,确定是哪种类型的调整; ⑷如果是LL型或RR型,只需应用扁担原理旋转一次,在旋转过程中,如果出现冲突,应用旋转优先原则调整冲突;如果是LR型或RL型,则需应用扁担原理旋转两次,第一次最小不平衡子树的根结点先不动,调整插入结点所在子树,第二次再调整最小不平衡子树,在旋转过程中,如果出现冲突,应用旋转优先原则调整冲突; ⑸计算调整后的平衡二叉树中各结点的平衡因子,检验是否因为旋转而破坏其他结点的平衡因子,以及调整后的平衡二叉树中是否存在平衡因子大于1的结点。 三.详细设计 树的内部变量 typedef struct BTNode {

平衡二叉树调整算法

平衡二叉树调整算法 在平衡二叉树中插入一个结点后造成不平衡,设最低的不平衡结点为A,并已知A的左孩子平衡因子为0,右孩子平衡因子为1,则应该做(C)型调整以使其平衡 A LL B LR C RL D RR 若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性。首先要找出插入新结点后失去平衡的最小子树根结点的指针。然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树。当失去平衡的最小子树被调整为平衡子树后,原有其他所有不平衡子树无需调整,整个二叉排序树就又成为一棵平衡二叉树。 失去平衡的最小子树是指以离插入结点最近,且平衡因子绝对值大于 1 的结点作为根的子树。假设用 A 表示失去平衡的最小子树的根结点,则调整该子树的操作可归纳为下列四种情况。 (1)LL型平衡旋转法 由于在 A 的左孩子 B 的左子树上插入结点 F ,使 A 的平衡因子由 1 增至2 而失去平衡。故需进行一次顺时针旋转操作。即将 A 的左孩子 B 向右上旋转代替 A 作为根结点, A 向右下旋转成为 B 的右子树的根结点。而原来B 的右子树则变成 A 的左子树。 (2)RR型平衡旋转法 由于在 A 的右孩子 C 的右子树上插入结点 F ,使 A 的平衡因子由-1 减至-2 而失去平衡。故需进行一次逆时针旋转操作。即将 A 的右孩子 C 向

左上旋转代替 A 作为根结点, A 向左下旋转成为 C 的左子树的根结点。而原来C 的左子树则变成 A 的右子树。 (3)LR型平衡旋转法 由于在 A 的左孩子 B 的右子数上插入结点 F ,使 A 的平衡因子由 1 增至2 而失去平衡。故需进行两次旋转操作(先逆时针,后顺时针)。即先将A 结点的左孩子B 的右子树的根结点 D 向左上旋转提升到 B 结点的位置,然后再把该D 结点向右上旋转提升到 A 结点的位置。即先使之成为LL型,再按LL型处理。 如图中所示,即先将圆圈部分先调整为平衡树,然后将其以根结点接到 A 的左子树上,此时成为LL 型,再按LL 型处理成平衡型。 (4)RL型平衡旋转法 由于在 A 的右孩子 C 的左子树上插入结点 F ,使 A 的平衡因子由-1 减至-2 而失去平衡。故需进行两次旋转操作(先顺时针,后逆时针),即先将A 结点的右孩子C 的左子树的根结点D 向右上旋转提升到C 结点的位置,然后再把该D 结点向左上旋转提升到 A 结点的位置。即先使之成为RR型,

数据结构课程设计:平衡二叉树

数据结构课程设计:平衡二叉树 目录 1 课程设计的目的和内容.............................................. 1 课程设计目的 ................................................ 1 1.1 1.2 主要内容 (1) 2 课程设计分析 (2) 2.1 程序的目的和要求 (2) 2.2 程序的主要数据和功能模块 (2) 3 详细设计 (5) 3.1 程序主要功能模块的伪代码算法 (5) 3.2 程序主要流程图 (8) 4 测试数据与测试结果................................................ 9 5 程序的使用和改进. (14) 5.1 用户使用说明 (14) 5.2 程序的改进 (14) 6 课程设计小结..................................................... 15 7 参考文献 (15) 1 平衡二叉树 1 课程设计的目的和内容 1.1 课程设计目的 复习二叉树的三叉链表存储结构和遍历方法。 掌握二叉排序树的特点和生成方法。

掌握平衡二叉树四种不平衡形态的判定和旋转为平衡的方法。 1.2 主要内容 (1)输入结点数据,构造二叉树的结点,按二叉排序树的规则插入该结点到三叉链表中; (2)通过插入函数InsertAVL(BSTNode* &T,int key)插入新结点到二叉树中,并递归调用插入函数本身,直到正确插入到二叉树中,并返回上次递归,每返回上次递归一次同时判断其平衡度bf,找到最小不平衡树的根结点p。 (3)判断最小不平衡树的平衡因子(bf)的值,若bf>1, 则调用左平衡函数LeftBalance(),若bf<-1,则调用右平衡函RightBalance(),再判断根结点p的左(右)孩子的平衡因子(共有LL型、LR型、RR型、RL型四种),然后判定得到的不平衡形态调用不同的旋转函数即可将其重新调整为平衡二叉树; (4)重复步骤(1)(2)(3),直到所有结点都插入到该平衡二叉树中为止; (5)输出该二叉树的前序(或者后序)序列和中序序列,手工恢复出该二叉树,检验其是否为平衡二叉树;并验证其中序序列的有序性。 2 平衡二叉树 2 课程设计分析 2.1 程序的目的和要求 (1)本程序演示平衡二叉树的插入,以及AVL的前序遍历和中序遍历,并且验证其中序遍历有序性。 (2)对平衡二叉树出现的的的LL,LR,RL,RR四种情况进行处理是其平衡。 (3)接着要实现平衡二叉树的插入,其中根据平衡二叉树插入的算法要不停的把插入的元素平衡地插入,需要判断平衡并调用左右旋转函数,更新平衡二叉树 2.2 程序的主要数据和功能模块 (1)程序主要数据 平衡二叉树左右子树的深度:ldep,rdep

实验报告平衡二叉树

实习报告 一、需求分析 1、问题描述 利用平衡二叉树实现一个动态查找表。 (1)实现动态查找表的三种基本功能:查找、插入和删除。 (2)初始时,平衡二叉树为空树,操作界面给出查找、插入和删除三种操作供选择。每种操作均要提示输入关键字。在查找时,如果查找的关键字不存在,则把其插入到平衡二叉树中。每次插入或删除一个结点后,应更新平衡二叉树的显示。 (3)每次操作的关键字都要从文件中读取,并且关键字的集合限定为短整型数字{1,2,3······},关键字出现的顺序没有限制,允许出现重复的关键字,并对其进行相应的提示。 (4)平衡二叉树的显示采用图形界面画出图形。 2、系统功能 打开数据文件,用文件中的关键字来演示平衡二叉树操作的过程。 3、程序中执行的命令包括: (1)(L)oad from data file //在平衡的二叉树中插入关键字; (2)(A)ppend new record //在平衡的二叉树中查找关键字; (3)(U)pate special record //显示调整过的平衡二叉树; (4)(D)elete special record //删除平衡二叉树中的关键字; (5)(Q)uit //结束。 4、测试数据: 平衡二叉树为: 图 1 插入关键字10之前的平衡二叉树 插入关键字:10; 调整后: 图 2 插入关键字10之后的平衡二叉树 删除关键字:14; 调整后:

图 3 删除关键字14后的平衡二叉树 查找关键字:11; 输出:The data is here! 图 3 查找关键字11后的平衡二叉树 二、概要设计 本次实验目的是为了实现动态查找表的三种基本功能:查找、插入和删除。动态查找表可有不同的表示方法,在此次实验中主要是以平衡二叉树的结构来表示实现的,所以需要两个抽象数据类型:动态查找表和二叉树。 1、动态查找表的抽象数据类型定义为: ADT DynamicSearchTable {数据对象D :D是具有相同特性的数据元素的集合。各个数据元素均含 有类型相同,可唯一标识数据元素的关键字。 数据关系R :数据元素同属于一个集合。 基本操作P : InitDSTable(&ST); 操作结果:构造一个空的动态查找表DT。 DestroyDSTable(&DT);

平衡二叉树算法及代码

Size Balanced Tree Size Balanced Tree(SBT)是一种平衡二叉查找树。它的论文由中国广东中山纪念中学的陈启峰于2006年底完成,并在Winter Camp 2007中发表。由于SBT的拼写很容易找到中文谐音,它常被中国的OIer们戏称为“傻X树”、“Super BT”等。但它的性能并不SB,编写起来也并不BT。恰恰相反,SBT易于实现,且据陈启峰论文中所言,“这是目前为止速度最快的高级二叉搜索树”。它能在O(logn)的时间内完成所有BST的相关操作。而且由于SBT赖以保持平衡的是Size域而不是其他“无用”的域,它可以很方便地实现动态顺序统计中的select和rank。 性质 Size Balanced Tree(SBT)是一种通过大小(Size)域来保持平衡的二叉搜索树,它也因此得名。它总是满足: 对于SBT的每一个结点t: 1. 性质(a) s[right[t] ]≥s[left[left[t]]],s[right[left[t]]] 2. 性质(b) s[left[t] ]≥s[right[right[t]]],s[left[right[t]]] 即每棵子树的大小不小于其兄弟的子树大小。 图1 如图(圈代表结点,三角代表SBT,下同): 1. s[R] ≥s[A],s[B] 2. s[L] ≥s[C],s[D] 旋转 SBT的旋转(Rotations)与其他许多高级BST相同。它是下面提到的Maintain操作的基础。

图2 [编辑]左旋转 右旋转 保持性质(Maintain) 当我们插入或删除一个结点后,SBT的大小就发生了改变。这种改变有可能导致性质(a)或(b)被破坏。这时,我们需要用Maintain操作来修复这棵树。Maintain操作是SBT中最具活力的一个独特过程;Maintain(T)用于修复以T为根的SBT。调用Maintain(T)的前提条件是T的子树都已经是SBT了。 我们需要讨论的有4种情况。由于性质a和性质b是对称的,所以我们仅仅详细的讨论性质a。

平衡二叉树学生信息管理系统程序

#include #include typedef struct A { char NO[10]; char name[10]; char birt[10]; char clas[10]; char sex[2]; }Elemtype; typedef struct B { Elemtype data; int bf; struct B *lchild; struct B *rchild; }node,*pnode; void left1(pnode &ptree,int &taller) { pnode p1,p2; if(ptree->bf==0) { ptree->bf=1; taller=1; } else if (ptree->bf==-1) { ptree->bf=0; taller=0; } else { p1=ptree->lchild; if (p1->bf==1) { ptree->lchild=p1->rchild; p1->rchild=ptree; ptree->bf=p1->bf=0; ptree=p1; } else if (p1->bf==-1)

{ p2=p1->rchild; p1->rchild=p2->lchild; p2->lchild=p1; ptree->lchild=p2->rchild; p2->rchild=ptree; if (p2->bf==0) ptree->bf=p1->bf=0; else if (p2->bf==1) { p1->bf=0; ptree->bf=-1; } else { p1->bf=1; ptree->bf=0; } ptree=p2; ptree->bf=0; } taller=0; } } void right1(pnode &ptree,int &taller) { pnode p1,p2; if(ptree->bf==0) { ptree->bf=-1; taller=1; } else if (ptree->bf==1) { ptree->bf=0; taller=0; } else { p1=ptree->rchild; if (p1->bf==-1) { ptree->rchild=p1->lchild;

平衡二叉树构建过程之我的理解

平衡二叉查找树 构建方法 郭建勇 coolkissmile@https://www.wendangku.net/doc/ff10813424.html,

定义 ?平衡二叉树(全称平衡二叉查找树) –是一棵二叉树 –是一颗二叉查找树 (对于任意节点x, 其左子树的所有节点都小于x, x的右子树的节点都大于等于x) –是一颗平衡树, 平衡意思是对于任意节点, 其左子树高度和右子树高度相差不超过1, 左右子树的高度差称为平衡因子 a, 也即 |a| <=1

辨析 ?平衡二叉树 vs 二叉查找树 二叉查找树也称作二叉排序树或者二叉搜索树 平衡二叉树的本质特点是左右子树的平衡, 而二 叉查找树是不要求平衡的 这也是为什么二叉搜索树在某些极端情况下搜索效率很低的原因: 高度太高, 接近线性效率 平衡二叉树就是为了尽量降低树的高度而提出来的.

插入 ?平衡二叉树的查找逻辑比较简单, 这里不讲了 ?构建平衡二叉树时的逻辑需要深刻理解?插入节点时如果左右子树平衡就不需要调整节点 ?如果左右不平衡那么就需要调整节点 ?由于不平衡没有一个统一的调整策略, 需要分情况看待, 左左, 右右, 左右, 右左.

100 110 ... new 出现不平衡--右右右右不平衡: 首先定位最小不平衡二叉树, 以100为根节点的树 如果新插入节点 new 是在100的右孩子(110)的右子树分支(以120为根的子树) 就称为右右不平衡105 120......

110 ... 105120 ...... new 思路: 把100的右子树高度降低1,或者把100的左子树高度加1 如果能把110为根的树提高到100的位置, 那么右子树高度就降低了1

数据结构课程设计:平衡二叉树

目录 1 课程设计的目的和内容 (1) 1.1 课程设计目的 (1) 1.2 主要内容 (1) 2 课程设计分析 (2) 2.1 程序的目的和要求 (2) 2.2 程序的主要数据和功能模块 (2) 3 详细设计 (5) 3.1 程序主要功能模块的伪代码算法 (5) 3.2 程序主要流程图 (8) 4 测试数据与测试结果 (9) 5 程序的使用和改进 (14) 5.1 用户使用说明 (14) 5.2 程序的改进 (14) 6 课程设计小结 (15) 7 参考文献 (15)

1 课程设计的目的和内容 1.1 课程设计目的 复习二叉树的三叉链表存储结构和遍历方法。 掌握二叉排序树的特点和生成方法。 掌握平衡二叉树四种不平衡形态的判定和旋转为平衡的方法。 1.2 主要内容 (1)输入结点数据,构造二叉树的结点,按二叉排序树的规则插入该结点到三叉链表中; (2)通过插入函数InsertAVL(BSTNode* &T,int key)插入新结点到二叉树中,并递归调用插入函数本身,直到正确插入到二叉树中,并返回上次递归,每返回上次递归一次同时判断其平衡度bf,找到最小不平衡树的根结点p。 (3)判断最小不平衡树的平衡因子(bf)的值,若bf>1, 则调用左平衡函数LeftBalance(),若bf<-1,则调用右平衡函RightBalance(),再判断根结点p的左(右)孩子的平衡因子(共有LL型、LR型、RR型、RL型四种),然后判定得到的不平衡形态调用不同的旋转函数即可将其重新调整为平衡二叉树; (4)重复步骤(1)(2)(3),直到所有结点都插入到该平衡二叉树中为止; (5)输出该二叉树的前序(或者后序)序列和中序序列,手工恢复出该二叉树,检验其是否为平衡二叉树;并验证其中序序列的有序性。

平衡二叉树的生成过程

二叉排序树变成平衡二叉树 莂蚅薈莈羁蚆薅对于二叉查找树,尽管查找、插入及删除操作的平均运行时间为O(logn),但是它们的最差运行时间都是O(n),原因在于对树的形状没有限制。 袅膆薈螃螅莇肀平衡二叉树又称为AVL树,它或者是一棵空树,或者是有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左右子树的深度之差的绝对值不超过1。二叉树的的平衡因子BF为:该结点的左子树的深度减去它的右子树的深度,则平衡二叉树的所有结点的平衡因子为只可能是:-1、0和1 羈羂芁羅腿芀膄一棵好的平衡二叉树的特征: 膁肂膅蚆葿蚂肅(1)保证有n个结点的树的高度为O(logn) 薀芅蒈蕿蒃芅蒅(2)容易维护,也就是说,在做数据项的插入或删除操作时,为平衡树所做的一些辅助操作时间开销为O(1) 蒄肆蝿羁莄芇莁一、平衡二叉树的构造 袈罿螃薄聿蒁莂在一棵二叉查找树中插入结点后,调整其为平衡二叉树。若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性。首先要找出插入新结点后失去平衡的最小子树根结点的指针。然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树。当失去平衡的最小子树被调整为平衡子树后,原有其他所有不平衡子树无需调整,整个二叉排序树就又成为一棵平衡二叉树 膈莁螄蚇蚁芄蚄1.调整方法 膂袄蒈袀螁袄莅(1)插入点位置必须满足二叉查找树的性质,即任意一棵子树的左结点都小于根结点,右结点大于根结点 肃羆羀薃羄膇芈(2)找出插入结点后不平衡的最小二叉树进行调整,如果是整个树不平衡,才进行整个树的调整。 螈膀肁膃罿蒈羄2.调整方式 莀袃莃薇袂蒂芃(1)LL型 蒀蒃荿肁芄蒃芆LL型:插入位置为左子树的左结点,进行向右旋转(LL表示的是在做子树的左结点进行插入) 羇袆芁袁薃肇蕿由于在A的左孩子B的左子树上插入结点F,使A的平衡因子由1变为2,成为不平衡的最小二叉树根结点。此时A结点顺时针右旋转,旋转过程中遵循“旋转优先”的规则,A结点替换D结点成为B结点的右子树,D结点成为A结点的左孩子。 蚈莁蚃肆罿虿节(2)RR型 薁膁膆蒇衿肄肆RR型:插入位置为右子树的右孩子,进行向左旋转 羃莆艿聿薂芆芆由于在A的右子树C的右子树插入了结点F,A的平衡因子由-1变为-2,成为不平衡的最小二叉树根结点。此时,A结点逆时针左旋转,遵循“旋转优先”的规则,A结点替换D结点成为C的左子树,D结点成为A的右子树。 薆螆膈莃蒆肇螀(3)LR型 薈莈羁蚆薅羀薀LR型:插入位置为左子树的右孩子,要进行两次旋转,先左旋转,再右旋转;第一次最小不平衡子树的根结点先不动,调整插入结点所在的子树,调整后的树变成LL型树,第二次再调整最小不平衡子树(根据LL型的调整规则,调整为平衡二叉树)。 薈螃螅莇肀莂蚅由于在A的左子树B的右子树上插入了结点F,A的平衡因子由1变为了2,成为不平衡的最小二叉树根结点。第一次旋转A结点不动,先将B的右子树的根结点D向左上旋转提升到B结点的位置,然后再把该D结点向右上旋转提升到A结点的位置。

平衡二叉树的实现及分析

【学生用】 西北农林科技大学信息工程学院《数据结构与C语言综合训练》实习报告 题目:AVL Tree的实现及分析 学号************ 姓名************* 专业班级计算机科学与技术103 指导教师******* 实践日期2011年7月8日-2011年7月18日

目录 一、综合训练目的与要求.................................. 错误!未定义书签。 二、综合训练任务描述 (1) 三、算法设计 (1) 四、详细设计及说明 (11) 五、调试与测试 (11) 六、实习日志 (13) 七、实习总结 (14) 八、附录:核心代码清单 (14)

一、综合训练目的与要求 本综合训练是计算机科学与技术专业重要的实践性环节之一,是在学生学习完《算法分析》课程后进行的综合练习。本课综合训练的目的和任务: 1. 巩固和加深学生对算法分析课程基本知识的理解和掌握; 2. 培养利用算法知识解决实际问题的能力; 3. 掌握利用程序设计语言进行算法程序的开发、调试、测试的能力; 4. 掌握书写算法设计说明文档的能力; 5. 提高综合运用算法、程序设计语言、数据结构知识的能力。 二、综合训练任务描述 1、创建一棵一般二元查找树。 2、判断一般二元查找数是否为AVL树。 3、一般二元查找树转化为AVL。 4、AVL树的插入与删除元素操作。 三、算法设计 (1) 文字描述 首先利用二元查找树的性质创建一棵一般的二元查找树,然后计算每个节点的bf值(平衡因子),通过bf值来判断所建立的二元查找树是否为平衡二叉树,不是的话就把它转换为平衡二叉树。首先把原二元查找树的每个节点的地址存放到一个循环队列中,然后把它们一一插入到建立的平衡二叉树里面,在建立的过程中一是要保证不能插入相同的节点,二是保证插入元素后平衡二叉树还是平衡的,这就要做到边插入边旋转,旋转有四种方式,分别是RR,RL,LR,LL。平衡二叉树的删除操作,首先要找到要删除的节点,要是没有找到的话应该报错,有的话就删除,删除要注意那三种情况,一是所删除节点只有左子树,一是所删除节点只有右子树,然后是所删除节点左右子树都有。 (2)框图

相关文档
相关文档 最新文档