平衡二叉树题目,平衡二叉树一定是完全二叉树
平衡二叉树问题
平衡因子一般是左子树的高度减去右子树的高度,因此从图上看,应刚插入的是31
从这个结点向根回溯,直到找到一个平衡因子的绝对值大于1的就停止(如果到根都没有就不用旋转)
然后向来路回退,根据来路连续三个结点的形状决定旋转的类型
你的图上32是+1、35是+1,30是-2,注意30、35、32这三个结点的路线是先右后左,因此旋转类型为先左后右双旋转
具体步骤如下:首先32和35向右旋转,35成为32的右子树,32的右子树给35
然后30和32向左旋转,30成为32的左子树,32的左子树成为30的右子树
【讨论】数据结构平衡二叉树题求解?
平衡二叉树,属于二叉排序树(左子树所有节点均小于它根节点的值,而右子树相反),所以构造树的时候按照二叉排序树,不断插入,就会发现插入51时,出现不平衡。
数据结构,第六题第2小题怎样构造平衡二叉树(出现相同关键字了)
这个问题,如果参考教材有规定就好处理。大多数教材,对二叉排序树来讲,是不可以有相同的关键字的。如果没有规定,可以这样去考虑,在插入第二个77时,不插入因为已存在77.这样就好处理了。对于第二问,同样平衡二叉树首先必须是二叉排序树。结果为:
67
/ \
27 87
/ \ / \
17 47 77 97
/ / \
07 37 57
题目3. 平衡二叉树算法查找树中某节点的时间复杂度是多少?
平均查找的时间复杂度为O(log n)。
平衡树的查找过程和排序树的相同。在查找过程中和给定值进行比较关键字个数不超过树的深度。
如果二叉树的元素个数为n,那么不管是对树进行插入节点、查找、删除节点都是log(n)次循环调用就可以了。它的时间复杂度相对于其他数据结构如数组等是最优的。
是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。常用算法有红黑树、AVL、Treap、伸展树等。
扩展资料:
二叉树也是递归定义的,其结点有左右子树之分,逻辑上二叉树算法有五种基本形态:
(1)空二叉树——(a)
(2)只有一个根结点的二叉树——(b);
(3)右子树为空的二叉树——(c);
(4)左子树为空的二叉树——(d);
(5)完全二叉树——(e)
注意:尽管二叉树与树有许多相似之处,但二叉树不是树的特殊情形。
参考资料来源:百度百科-二叉树算法
2010年计算机专业统考的一题关于平衡二叉树
插入48之后属于右左双旋转的情况,按照图示的方法先做右单旋转,再做左单旋转
右单旋转:以37为轴,53顺时针旋转(向下),原本是37左孩子的48成为53的左孩子
24的右孩子由53变为37
左单旋转:仍然以37为轴,24逆时针旋转(向下),成为37的左孩子
(如有误敬请指正)
平衡二叉树
以前做的。
一、 需求分析
1. 本程序是是利用平衡二叉树实现一个动态查找表,实现动态查找表的三种基本功能:查找、插入和删除。
2. 初始,平衡二叉树为空树,可以按先序输入平衡二叉树,以输入0结束,中间以回车隔开,创建好二叉树后,可以对其查找,再对其插入,输入0结束插入,再可以对其删除,输入0结束,每次插入或删除一个结点后,更新平衡二叉树的显示。
3. 本程序以用户和计算机的对话方式执行,根据计算机终端显示:“提示信息”下,用户可由键盘输入要执行的操作。
4. 测试数据(附后)
二、 概要设计
1. 抽象数据类型动态查找表的定义如下:
ADT DynamicSearchTable{
数据结构D:D是具有相同特性的数据元素的集合。各个数据元素含有类型相同,可惟一标识数据元素的关键字。
数据关系R:数据元素同属一个集合。
基本操作P:
InitDSTable(DT);
操作结果:构造一个空的动态查找表DT。
DestroyDSTable(DT);
初试条件:动态查找表DT存在。
操作结果: 销毁动态查找表DT。
SearchDSTable(DT,key);
初试条件:动态查找表DT存在,key为和关键字类型相同的给定值。
操作结果: 若DT中存在其关键字等于key的数据元素,则函数值为该元素的值或表中的位置,否则为“空”。
InsertDSTable(DT,e);
初试条件:动态查找表DT存在,e为待插入的数据元素。
操作结果: 若DT中不存在其关键字等于e. key的数据元素,则插入e到DT。
DeleteDSTable(DT,key);
初试条件:动态查找表DT存在,key为和关键字类型相同的给定值。
操作结果: 若DT中存在其关键字等于key的数据元素,则删除之。
TraverseDSTable(DT,Visit());
初试条件:动态查找表DT存在,Visit()是结点操作的应用函数。
操作结果: 按某种次序对DT的每个结点调用函数Visit()一次且至多
一次。一但Visit()失败,则操作失败。
}ADT DynamicSearchTable
2. 本程序包含两个模块:
Void main(){
Do{
接受命令(根据提示输入终点城市和起点城市的序号);
处理命令;
}while(“命令”=“退出”);
}
3.本程序只有两个模块,调用关系简单
主程序模块
平衡二叉树的模块
三、 详细设计
1. 根据题目要求和查找的基本特点,其结点类型
typedef struct BSTnode{
int data;
int bf;
struct BSTnode *lchild,*rchild;
}BSTnode,*bstree;
#define LH +1
#define EH 0
#define RH -1
/-----------------------------************对平衡二叉树的操作
bstree InsertAVL(bstree T, int e);
////////在平衡二叉树中插入结点。
int FindAVL(bstree p,int e);
////////查找平衡二叉树中是否有结点e。
bstree DeleteAVL(bstree T,int e)
////////删除平衡平衡二叉树的结点e,并保持平衡二叉树的性质。
int Preordertraverse(bstree T)
////////按先序遍历平衡二叉树。
/------------------------************平衡二叉树的操作的详细算法
bstree InsertAVL(bstree T, int e)
{
bstree p;
//插入新结点,树长高置taller为TRUE
if(!T) {
T=(bstree)malloc(sizeof(BSTnode));
T-data=e;
T-lchild=T-rchild=NULL;
T-bf=EH;
taller=TRUE;
}
else {
//树中存在和e有相同关键字的结点则不再插入
if(e==T-data){
taller=FALSE;
return NULL;
}
//值小于则继续在树的左子树中搜索
if(e T-data){
//插入到左子树且左子树长高
p=InsertAVL(T-lchild,e);
if(p){
T-lchild=p;
if(taller) {
switch(T-bf){ //检查*T的平衡度
case LH: //原本左子树比右子树高,需要做左平衡处理
T=LeftBalance(T);
taller=FALSE;
break;
case EH: //原本左子树和右子树同高,现因左子树争高而使树增高
T-bf=LH;
taller=TRUE;
break;
case RH: //原本右子树比左子树高,现在左右子树等高
T-bf=EH;
taller=FALSE;
break;
}///////switch(T-bf)
}///////if(taller)
}/////if(p)
}///////if(e T-data)
//继续在*T的右子树中搜索
else{
//插入到右子树且使右子树长高
p=InsertAVL(T-rchild,e);
if (p){
T-rchild=p;
if(taller) {
switch(T-bf){ //检查*T的平衡度
case LH: //原本左子树比右子树高,现在左右子树等高
T-bf=EH;
taller=FALSE;
break;
case EH: //原本左子树和右子树同高,现因右子树增高而使树增高
T-bf=RH;
taller=TRUE;
break;
case RH: //原本右子树比左子树高,需要做右平衡处理
T=RightBalance(T);
taller=FALSE;
break;
}//////switch(T-bf)
}/////if(taller)
}/////if (p)
}//////if(e T-data)
}///////else
return T;
}
int Preordertraverse(bstree T){
if(T){
printf(" %d %d\n",T-data,T-bf);
Preordertraverse(T-lchild);
Preordertraverse(T-rchild);
}
return 1;
}
int FindAVL(bstree p,int e){
if(p==NULL)return NULL;
else if(e==p-data) return true;
else if(ep-data){
p=p-lchild;
return FindAVL(p, e);
}////左子树上查找
else {
p=p-rchild;
return FindAVL( p, e);
}////右子树上查找
}
bstree DeleteAVL(bstree T,int e){
//删除后要保证该二叉树还是平衡的
int n,m=0;/////标记
bstree q;
if(!T)return NULL;
else {
if(e==T-data) {////直接删除
n=Delete(T,e);
m=n;
if(m!=0) {
q=T;
DeleteAVL(T,m);
q-data=m;}
}
else {
if(eT-data){////在左子树上寻找
DeleteAVL(T-lchild,e);
if(shorter){
switch(T-bf){
case LH:T-bf=EH;shorter=true;break;
case EH:T-bf=RH;shorter=false;break;
case RH:Delete_Rightbalance(T);shorter=true;break;
}////switch(T-bf)
}/////if(shorter)
}/////if(eT-data)
else{ /////////在右子树上寻找
DeleteAVL(T-rchild,e);
if(shorter)
switch(T-bf){
case LH:Delete_Leftbalance(T);shorter=true;break;
case EH:T-bf=LH;shorter=false;break;
case RH:T-bf=EH;shorter=true;break;
}////////switch(T-bf)
}////////在右子数上寻找完
}////////在左右子上完
}///////////删除完
return T;
}
2. 主程序和其他伪码算法
void main(){
while(e!=0){
if(e!=0) InsertAVL(T,e);
}
while(d!=0){
if(d!=0) InsertAVL(T,d);
Preordertraverse(T);
}
c=FindAVL(T,t);
if(c==1)printf("有要查找的节点\n");
else printf("无要查找的节点\n");
do{
DeleteAVL(T,b);
Preordertraverse(T);
}while(b==1);
}
///右旋
bstree R_Rotate(bstree p){
bstree lc;
lc=p-lchild;
p-lchild=lc-rchild;
lc-rchild=p;
p=lc;
return p;
}
////左旋
bstree L_Rotate(bstree p){
bstree rc;
rc=p-rchild;
p-rchild=rc-lchild;
rc-lchild=p;
p=rc;
return p;
}
/////左平衡处理
bstree LeftBalance(bstree T){
bstree lc,rd;
lc=T-lchild; //lc指向*T的左子树根结点
switch(lc-bf) { //检查*T的左子树平衡度,并做相应的平衡处理
case LH: //新结点插入在*T的左孩子的左子树上,要做单右旋处理
T-bf=lc-bf=EH;
T=R_Rotate(T);
break;
case RH: //新结点插入在*T的左孩子的右子树上,要做双旋处理
rd=lc-rchild; //rd指向*T的左孩子的右子树根
switch(rd-bf){ //修改*T及其左孩子的平衡因子
case LH:
T-bf=RH;
lc-bf=EH;
break;
case EH:
T-bf=lc-bf=EH;
break;
case RH:
T-bf=EH;
lc-bf=LH;
break;
}//////////switch(rd-bf)
rd-bf=EH;
T-lchild=L_Rotate(T-lchild); //对*T的左孩子做左旋平衡处理
T=R_Rotate(T); //对*T做右旋处理
}////////switch(lc-bf)
return T;
}
////右平衡处理
bstree RightBalance(bstree T)
{
bstree rc,ld;
rc=T-rchild; //rc指向*T的右子树根结点
switch(rc-bf) { //检查*T的右子树平衡度,并做相应的平衡处理
case RH: //新结点插入在*T的右孩子的右子树上,要做单右旋处理
T-bf=rc-bf=EH;
T=L_Rotate(T);
break;
case LH: //新结点插入在*T的右孩子的左子树上,要做双旋处理
ld=rc-lchild; //ld指向*T的右孩子的左子树根
switch(ld-bf){ //修改*T及其右孩子的平衡因子
case LH:
T-bf=EH;
rc-bf=RH;
break;
case EH:
T-bf=rc-bf=EH;
break;
case RH:
T-bf=LH;
rc-bf=EH;
break;
}///switch(ld-bf)
ld-bf=EH;
T-rchild=R_Rotate(T-rchild); //对*T的右孩子做右旋平衡处理
T=L_Rotate(T); //对*T做左旋处理
}/////switch(rc-bf)
return T;
}
int Delete(bstree T,int e){
//删除结点
bstree p,q;
e=0;
p=T;
if(!T-rchild) {//右子数为空需要重接它的左子数
T=T-lchild;
free(p);
shorter=true;
}
else if(!T-lchild) {//重接它的右子数
T=T-rchild;
free(p);
shorter=true;
}
else{ //左右子数均不空
q=T-lchild;
while(q-rchild!=NULL){//转左,然后向右到尽头
q=q-rchild;
}
e=q-data;
}
return e;
}
void Delete_Rightbalance(bstree T){
///////////删除在左子树上的,相当于插入在右子树
bstree rc=T-rchild,ld;
switch(rc-bf){
case LH://///////双旋 ,先右旋后左旋
ld=rc-lchild;
rc-lchild=ld-rchild;
ld-rchild=rc;
T-rchild=rc-lchild;
rc-lchild=T;
switch(ld-bf) {
case LH:T-bf=EH;
rc-bf=RH;
break;
case EH:T-bf=rc-bf=EH;
break;
case RH:T-bf=LH;
rc-bf=EH;
break;
}
ld-bf=EH;
T=rc;
shorter=true;break;
case EH:///////删除在左子树,相当于插入在右子树,左单旋
T-rchild=rc-lchild;
rc-lchild=T;
rc-bf=LH;
T-bf=RH;
T=rc;
shorter=EH;break;
case RH:///////删除在左子树,相当于插入在右子树,左单旋
T-rchild=rc-lchild;
rc-lchild=T;
rc-bf=T-bf=EH;
T=rc;
shorter=true;break;
}
}
void Delete_Leftbalance(bstree T)/////删除右子树上的,相当于插入在左子树上
{
bstree p1,p2;
p1=T-lchild;
switch(p1-bf) {
case LH:T-lchild=p1-rchild;//////右旋
p1-rchild=T;
p1-bf=T-bf=EH;
T=p1;
shorter=true;
break;
case EH:T-lchild=p1-rchild;///////右旋
p1-rchild=T;
p1-bf=RH;
T-bf=LH;
T=p1;
shorter=false;
break;
case RH:p2=p1-rchild;//////////右双旋
p1-rchild=p2-lchild;
p2-lchild=p1;
T-lchild=p2-rchild;
p2-rchild=T;
switch(p2-bf){
case LH:T-bf=RH;p1-bf=EH;break;
case EH:T-bf=EH;p1-bf=EH;break;
case RH:T-bf=EH;p1-bf=LH;break;
}
p2-bf=EH;
T=p2;
shorter=true;break;
}
}
3. 函数的调用关系图
Main
InsertAVL Preordertraverse FindAVL DeleteAVL
四、 调试分析
1. 在开始对平衡二叉树的插入后,再做平衡处理时,特别是在做双向旋转平衡处理后的更新时,费了一些时间;
2. 在做平衡二叉树的删除时,当删除结点左右孩子均在时,开始直接用左子树的最大数代替,然后直接删除结点,结果导致删除了将要删除的结点及其孩子均删除了,后来将要删除的结点用左子树的最大树代替后,对左子树的最大结点做好标记,然后再做对其做删除处理。
3. 本程序算法基本简单,没有多大困难,就是在分析做双旋平衡处理的更新时,开始思路有些混乱,后来就好了;
五、 用户手册
1. 本程序的运行环境为DOS操作系统,执行文件为Balanced Tree.exe。
2. 进入演示程序后,按广度遍历输入平衡二叉树,中间以回车键隔开,输入0为结束;再输入要插入的结点,输入0结束,再输入要查找的结点,最后可以输入要删除的结点,输入0结束
六、 测试结果
先按广度遍历创建平衡二叉树(亦可一个一个的插入二叉树的结点)(50 20 60 10 30 55 70 5 15 25 58 90) ,输入0结束,然后可插入结点(39),其会显示插入后的二叉树,输入0,不再插入;输入要查找结点(6),输入要删除的结点(20),其显示如下:
七、 附录
Balance Tree.cpp