数据结构课程设计---二叉排序树和平衡二叉树的判别
数据结构平衡二叉树的操作演示

平衡二叉树操作的演示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{ElemType data;int bf;struct BSTNode *lchild ,*rchild;} BSTNode,* BSTree;Status SearchBST(BSTree T,ElemType e)//查找void R_Rotate(BSTree &p)//右旋void L_Rotate(BSTree &p)//左旋void LeftBalance(BSTree &T)//插入平衡调整void RightBalance(BSTree &T)//插入平衡调整Status InsertAVL(BSTree &T,ElemType e,int &taller)//插入void DELeftBalance(BSTree &T)//删除平衡调整void DERightBalance(BSTree &T)//删除平衡调整Status Delete(BSTree &T,int &shorter)//删除操作Status DeleteAVL(BSTree &T,ElemType e,int &shorter)//删除操作void merge(BSTree &T1,BSTree &T2)//合并操作void splitBSTree(BSTree T,ElemType e,BSTree &T1,BSTree &T2)//分裂操作void PrintBSTree(BSTree &T,int lev)//凹入表显示附录源代码:#include<stdio.h>#include<stdlib.h>//#define TRUE 1//#define FALSE 0//#define OK 1//#define ERROR 0#define LH +1#define EH 0#define RH -1//二叉类型树的类型定义typedef int Status;typedef int ElemType;typedef struct BSTNode{ElemType data;int bf;//结点的平衡因子struct BSTNode *lchild ,*rchild;//左、右孩子指针} BSTNode,* BSTree;/*查找算法*/Status SearchBST(BSTree T,ElemType e){if(!T){return 0; //查找失败}else if(e == T->data ){return 1; //查找成功}else if (e < T->data){return SearchBST(T->lchild,e);}else{return SearchBST(T->rchild,e);}}//右旋void R_Rotate(BSTree &p){BSTree lc; //处理之前的左子树根结点lc = p->lchild; //lc指向的*p的左子树根结点p->lchild = lc->rchild; //lc的右子树挂接为*P的左子树lc->rchild = p;p = lc; //p指向新的根结点}//左旋void L_Rotate(BSTree &p){BSTree rc;rc = p->rchild; //rc指向的*p的右子树根结点p->rchild = rc->lchild; //rc的左子树挂接为*p的右子树rc->lchild = p;p = rc; //p指向新的根结点}//对以指针T所指结点为根结点的二叉树作左平衡旋转处理,//本算法结束时指针T指向新的根结点void LeftBalance(BSTree &T){BSTree lc,rd;lc=T->lchild;//lc指向*T的左子树根结点switch(lc->bf){ //检查*T的左子树的平衡度,并做相应的平衡处理case LH: //新结点插入在*T的左孩子的左子树,要做单右旋处理T->bf = lc->bf=EH;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;}rd->bf=EH;L_Rotate(T->lchild); //对*T的左子树作左旋平衡处理R_Rotate(T); //对*T作右旋平衡处理}}//右平衡旋转处理void RightBalance(BSTree &T){BSTree rc,ld;rc=T->rchild;switch(rc->bf){case RH:T->bf= rc->bf=EH;L_Rotate(T);break;case LH:ld=rc->lchild;switch(ld->bf){case LH: T->bf=RH; rc->bf=EH;break;case EH: T->bf=rc->bf=EH;break;case RH: T->bf = EH; rc->bf=LH;break;}ld->bf=EH;R_Rotate(T->rchild);L_Rotate(T);}}//插入结点Status InsertAVL(BSTree &T,ElemType e,int &taller){//taller反应T长高与否if(!T){//插入新结点,树长高,置taller为trueT= (BSTree) malloc (sizeof(BSTNode));T->data = e;T->lchild = T->rchild = NULL;T->bf = EH;taller = 1;}else{if(e == T->data){taller = 0;return 0;}if(e < T->data){if(!InsertAVL(T->lchild,e,taller))//未插入return 0;if(taller)//已插入到*T的左子树中且左子树长高switch(T->bf){//检查*T的平衡度,作相应的平衡处理case LH:LeftBalance(T);taller = 0;break;case EH:T->bf = LH;taller = 1;break;case RH:T->bf = EH;taller = 0;break;}}else{if (!InsertAVL(T->rchild,e,taller)){return 0;}if(taller)//插入到*T的右子树且右子树增高switch(T->bf){//检查*T的平衡度case LH:T->bf = EH;taller = 0;break;case EH:T->bf = RH;taller = 1;break;case RH:RightBalance(T);taller = 0;break;}}}return 1;}void DELeftBalance(BSTree &T){//删除平衡调整BSTree lc,rd;lc=T->lchild;switch(lc->bf){case LH:T->bf = EH;//lc->bf= EH;R_Rotate(T);break;case EH:T->bf = EH;lc->bf= EH;R_Rotate(T);break;case RH:rd=lc->rchild;switch(rd->bf){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;}rd->bf=EH;L_Rotate(T->lchild);R_Rotate(T);}}void DERightBalance(BSTree &T) //删除平衡调整{BSTree rc,ld;rc=T->rchild;switch(rc->bf){case RH:T->bf= EH;//rc->bf= EH;L_Rotate(T);break;case EH:T->bf= EH;//rc->bf= EH;L_Rotate(T);break;case LH:ld=rc->lchild;switch(ld->bf){case LH: T->bf=RH; rc->bf=EH;break;case EH: T->bf=rc->bf=EH;break;case RH: T->bf = EH; rc->bf=LH;break;}ld->bf=EH;R_Rotate(T->rchild);L_Rotate(T);}}void SDelete(BSTree &T,BSTree &q,BSTree &s,int &shorter){if(s->rchild){SDelete(T,s,s->rchild,shorter);if(shorter)switch(s->bf){case EH:s->bf = LH;shorter = 0;break;case RH:s->bf = EH;shorter = 1;break;case LH:DELeftBalance(s);shorter = 0;break;}return;}T->data = s->data;if(q != T)q->rchild = s->lchild;elseq->lchild = s->lchild;shorter = 1;}//删除结点Status Delete(BSTree &T,int &shorter){ BSTree q;if(!T->rchild){q = T;T = T->lchild;free(q);shorter = 1;}else if(!T->lchild){q = T;T= T->rchild;free(q);shorter = 1;}else{SDelete(T,T,T->lchild,shorter);if(shorter)switch(T->bf){case EH:T->bf = RH;shorter = 0;break;case LH:T->bf = EH;shorter = 1;break;case RH:DERightBalance(T);shorter = 0;break;}}return 1;}Status DeleteAVL(BSTree &T,ElemType e,int &shorter){ int sign = 0;if (!T){return sign;}else{if(e == T->data){sign = Delete(T,shorter);return sign;}else if(e < T->data){sign = DeleteAVL(T->lchild,e,shorter);if(shorter)switch(T->bf){case EH:T->bf = RH;shorter = 0;break;case LH:T->bf = EH;shorter = 1;break;case RH:DERightBalance(T);shorter = 0;break;}return sign;}else{sign = DeleteAVL(T->rchild,e,shorter);if(shorter)switch(T->bf){case EH:T->bf = LH;shorter = 0;break;case RH:T->bf = EH;break;case LH:DELeftBalance(T);shorter = 0;break;}return sign;}}}//合并void merge(BSTree &T1,BSTree &T2){int taller = 0;if(!T2)return;merge(T1,T2->lchild);InsertAVL(T1,T2->data,taller);merge(T1,T2->rchild);}//分裂void split(BSTree T,ElemType e,BSTree &T1,BSTree &T2){ int taller = 0;if(!T)return;split(T->lchild,e,T1,T2);if(T->data > e)InsertAVL(T2,T->data,taller);elseInsertAVL(T1,T->data,taller);split(T->rchild,e,T1,T2);}//分裂void splitBSTree(BSTree T,ElemType e,BSTree &T1,BSTree &T2){ BSTree t1 = NULL,t2 = NULL;split(T,e,t1,t2);T1 = t1;T2 = t2;return;}//构建void CreatBSTree(BSTree &T){int num,i,e,taller = 0;printf("输入结点个数:");scanf("%d",&num);printf("请顺序输入结点值\n");for(i = 0 ;i < num;i++){printf("第%d个结点的值",i+1);scanf("%d",&e);InsertAVL(T,e,taller) ;}printf("构建成功,输入任意字符返回\n");getchar();getchar();}//凹入表形式显示方法void PrintBSTree(BSTree &T,int lev){int i;if(T->rchild)PrintBSTree(T->rchild,lev+1);for(i = 0;i < lev;i++)printf(" ");printf("%d\n",T->data);if(T->lchild)PrintBSTree(T->lchild,lev+1);void Start(BSTree &T1,BSTree &T2){int cho,taller,e,k;taller = 0;k = 0;while(1){system("cls");printf(" 平衡二叉树操作的演示 \n\n");printf("********************************\n");printf(" 平衡二叉树显示区 \n");printf("T1树\n");if(!T1 )printf("\n 当前为空树\n");else{PrintBSTree(T1,1);}printf("T2树\n");if(!T2 )printf("\n 当前为空树\n");elsePrintBSTree(T2,1);printf("\n********************************************************************* *********\n");printf("T1操作:1.创建 2.插入 3.查找 4.删除 10.分裂\n");printf("T2操作:5.创建 6.插入 7.查找 8.删除 11.分裂\n");printf(" 9.合并 T1,T2 0.退出\n");printf("*********************************************************************** *******\n");printf("输入你要进行的操作:");scanf("%d",&cho);switch(cho){case 1:CreatBSTree(T1);break;case 2:printf("请输入要插入关键字的值");scanf("%d",&e);InsertAVL(T1,e,taller) ;break;case 3:printf("请输入要查找关键字的值");scanf("%d",&e);if(SearchBST(T1,e))printf("查找成功!\n");elseprintf("查找失败!\n");printf("按任意键返回87"); getchar();getchar();break;case 4:printf("请输入要删除关键字的值"); scanf("%d",&e);if(DeleteAVL(T1,e,k))printf("删除成功!\n");elseprintf("删除失败!\n");printf("按任意键返回");getchar();getchar();break;case 5:CreatBSTree(T2);break;case 6:printf("请输入要插入关键字的值"); scanf("%d",&e);InsertAVL(T2,e,taller) ;break;case 7:printf("请输入要查找关键字的值"); scanf("%d",&e);if(SearchBST(T2,e))printf("查找成功!\n");elseprintf("查找失败!\n");printf("按任意键返回");getchar();getchar();break;case 8:printf("请输入要删除关键字的值"); scanf("%d",&e);if(DeleteAVL(T2,e,k))printf("删除成功!\n");elseprintf("删除失败!\n");printf("按任意键返回");getchar();getchar();break;case 9:merge(T1,T2);T2 = NULL;printf("合并成功,按任意键返回"); getchar();getchar();break;case 10:printf("请输入要中间值字的值"); scanf("%d",&e);splitBSTree(T1,e,T1,T2) ;printf("分裂成功,按任意键返回"); getchar();getchar();break;case 11:printf("请输入要中间值字的值"); scanf("%d",&e);splitBSTree(T2,e,T1,T2) ;printf("分裂成功,按任意键返回"); getchar();getchar();break;case 0:system("cls");exit(0);}}}main(){BSTree T1 = NULL;BSTree T2 = NULL;Start(T1,T2);}。
二叉排序树

9
第9章
第三节
二、二叉排序树(插入)
查找
动态查找表
二叉排序树是一种动态查找表
当树中不存在查找的结点时,作插入操作
新插入的结点一定是叶子结点(只需改动一个 结点的指针) 该叶子结点是查找不成功时路径上访问的最后 一个结点的左孩子或右孩子(新结点值小于或 大于该结点值) 10
第9章
第三节
查找
19
在二叉排序树中查找关 键字值等于37,88,94
3
第9章
第三节
查找
动态查找表
二、二叉排序树(查找函数)中结点结构定义 二叉排序树通常采用二叉链表的形式进行存 储,其结点结构定义如下:
typedef struct BiNode { int data; BiNode *lChild, *rChild; }BiNode,*BitTree;
4
第9章
第三节
查找
动态查找表
2、二叉排序树的定义 定义二叉排序树所有用到的变量 BitTree root; int
//查找是否成功(1--成功,0--不成功) //查找位置(表示在BisCount层中的第几个位置
BisSuccess;
int
int
BisPos;
BisCount;
//查找次数(相当于树的层数)
7
第9章
第三节
查找
动态查找表
二、二叉排序树(查找函数)
else { BisSuccess = 0; root=GetNode(k);//查找不成功,插入新的结点}
} BiNode * GetNode(int k) { BiNode *s; s = new BiNode; s->data = k; s->lChild = NULL; s->rChild = NULL; return(s);}
二叉排序树的判定算法

⼆叉排序树的判定算法//函数功能:⼆叉排序树的判定算法/*算法思想:根据⼆叉树的特点“其中序遍历序列为有序序列”,对⼆叉树进⾏中序遍历,同时检查当前结点与其中前驱关键字值的⼤⼩。
*///中序遍历过程中判定给定的⼆叉树是否为⼆叉排序树,⼊是返会true,否则返回false//pre指向中序前驱结点,初值为NULL1 typedef struct treeNode2 {3int data; //⼆叉排序树的元素类型为int4struct treeNode *l,*r;5 }treeNode,*BiTree;67/*8中序遍历⼆叉树,root为根节点,pre初始值为null。
910*/1112bool Is_BS_Tree(BiTree root,BiTree pre)13 {14if(!root)15 {//空⼆叉树也是⼆叉排序树,所以返回true。
16return true;17 }18if(Is_BS_Tree(root->l,pre))19 {//若左⼦树是⼆叉排序树。
20//是否为⼆叉排序树取决于前驱值和根节点值的⼤⼩。
21if((pre==null)||(pre->data<root->data))22 {23 pre=root;24//再次判断右⼦树是否为⼆叉排序树。
25return Is_BS_Tree(root->l,pre);26 }27 }28//以上情况出现异常,则返回false。
29return false;30 }。
数据结构之二叉树(BinaryTree)

数据结构之⼆叉树(BinaryTree)⽬录导读 ⼆叉树是⼀种很常见的数据结构,但要注意的是,⼆叉树并不是树的特殊情况,⼆叉树与树是两种不⼀样的数据结构。
⽬录 ⼀、⼆叉树的定义 ⼆、⼆叉树为何不是特殊的树 三、⼆叉树的五种基本形态 四、⼆叉树相关术语 五、⼆叉树的主要性质(6个) 六、⼆叉树的存储结构(2种) 七、⼆叉树的遍历算法(4种) ⼋、⼆叉树的基本应⽤:⼆叉排序树、平衡⼆叉树、赫夫曼树及赫夫曼编码⼀、⼆叉树的定义 如果你知道树的定义(有限个结点组成的具有层次关系的集合),那么就很好理解⼆叉树了。
定义:⼆叉树是n(n≥0)个结点的有限集,⼆叉树是每个结点最多有两个⼦树的树结构,它由⼀个根结点及左⼦树和右⼦树组成。
(这⾥的左⼦树和右⼦树也是⼆叉树)。
值得注意的是,⼆叉树和“度⾄多为2的有序树”⼏乎⼀样,但,⼆叉树不是树的特殊情形。
具体分析如下⼆、⼆叉树为何不是特殊的树 1、⼆叉树与⽆序树不同 ⼆叉树的⼦树有左右之分,不能颠倒。
⽆序树的⼦树⽆左右之分。
2、⼆叉树与有序树也不同(关键) 当有序树有两个⼦树时,确实可以看做⼀颗⼆叉树,但当只有⼀个⼦树时,就没有了左右之分,如图所⽰:三、⼆叉树的五种基本状态四、⼆叉树相关术语是满⼆叉树;⽽国际定义为,不存在度为1的结点,即结点的度要么为2要么为0,这样的⼆叉树就称为满⼆叉树。
这两种概念完全不同,既然在国内,我们就默认第⼀种定义就好)。
完全⼆叉树:如果将⼀颗深度为K的⼆叉树按从上到下、从左到右的顺序进⾏编号,如果各结点的编号与深度为K的满⼆叉树相同位置的编号完全对应,那么这就是⼀颗完全⼆叉树。
如图所⽰:五、⼆叉树的主要性质 ⼆叉树的性质是基于它的结构⽽得来的,这些性质不必死记,使⽤到再查询或者⾃⼰根据⼆叉树结构进⾏推理即可。
性质1:⾮空⼆叉树的叶⼦结点数等于双分⽀结点数加1。
证明:设⼆叉树的叶⼦结点数为X,单分⽀结点数为Y,双分⽀结点数为Z。
数据结构第九章 查找part5

二叉平衡树是二叉查找树的另一种形 式,其特点为:
树中每个结点的左、右子树深度之 差的绝对值不大于1,即 hL hR 1 。 例如:
4
2 5 5
8
2
4
8
是平衡树
1
不是平衡树
1
-1
1
0
0
0
1
0
-1
1 0
平衡二叉树
2 -1 0 0 1 0 0 0 0 0 -1 -2 1
不平衡的二叉树
构造二叉平衡(查找)树的方法是:
二、二叉平衡树
何谓“二叉平衡树”? 如何构造“二叉平衡树”? 二叉平衡树的查找性能分析
二叉平衡树
又称AVL树。它或者是一棵空树,或者是 具有下列性质的二叉树:它的左子树或右子 树都是平衡二叉树,且左子树和右子树的深 度之差的绝对值不超过1。
平衡因子
二叉树上任一结点的左子树深度减去右 子树深度的差值,称为此结点的平衡因子。
if (i>0 && p->key[i]==K) found=TRUE; else { q=p; p=p->ptr[i]; } // q 指示 p 的双亲 } if (found) return (p,i,1); else return (q,i,0);
// 查找成功 // 查找不成功
三、 B - 树
1.定义 2.查找过程 3.插入操作
4.删除操作
5.查找性能的分析
1.B-树的定义
B-树是一种平衡的多路查找树,它在文 件系统中很有用。
一棵m阶的B-树,或为空树,或为满足下列特 性的m叉树:
① 树中每个结点至多有m 棵子树; ② 若根结点不是叶子结点,则至少有两棵子 树;
平衡二叉树详解

平衡⼆叉树详解平衡⼆叉树详解简介平衡⼆叉树(Balanced Binary Tree)具有以下性质:它是⼀棵空树或它的左右两个⼦树的⾼度差的绝对值不超过1,并且左右两个⼦树都是⼀棵平衡⼆叉树。
平衡⼆叉树的常⽤实现⽅法有红⿊树、AVL、替罪⽺树、Treap、伸展树等。
其中最为经典当属AVL树,我们总计⽽⾔就是:平衡⼆叉树是⼀种⼆叉排序树,其中每⼀个结点的左⼦树和右⼦树的⾼度差⾄多等于1。
性值AVL树具有下列性质的⼆叉树(注意,空树也属于⼀种平衡⼆叉树):l 它必须是⼀颗⼆叉查找树l 它的左⼦树和右⼦树都是平衡⼆叉树,且左⼦树和右⼦树的深度之差的绝对值不超过1。
l 若将⼆叉树节点的平衡因⼦BF定义为该节点的左⼦树的深度减去它的右⼦树的深度,则平衡⼆叉树上所有节点的平衡因⼦只可能为-1,0,1.l 只要⼆叉树上有⼀个节点的平衡因⼦的绝对值⼤于1,那么这颗平衡⼆叉树就失去了平衡。
实现平衡⼆叉树不平衡的情形:把需要重新平衡的结点叫做α,由于任意两个结点最多只有两个⼉⼦,因此⾼度不平衡时,α结点的两颗⼦树的⾼度相差2.容易看出,这种不平衡可能出现在下⾯4中情况中:1.对α的左⼉⼦的左⼦树进⾏⼀次插⼊2.对α的左⼉⼦的右⼦树进⾏⼀次插⼊3.对α的右⼉⼦的左⼦树进⾏⼀次插⼊4.对α的右⼉⼦的右⼦树进⾏⼀次插⼊(1)LR型(2)LL型(3)RR型(4)RL型完整代码#include<stdio.h>#include<stdlib.h>//结点设计typedef struct Node {int key;struct Node *left;struct Node *right;int height;} BTNode;int height(struct Node *N) {if (N == NULL)return0;return N->height;}int max(int a, int b) {return (a > b) ? a : b;}BTNode* newNode(int key) {struct Node* node = (BTNode*)malloc(sizeof(struct Node));node->key = key;node->left = NULL;node->right = NULL;node->height = 1;return(node);}//ll型调整BTNode* ll_rotate(BTNode* y) {BTNode *x = y->left;y->left = x->right;x->right = y;y->height = max(height(y->left), height(y->right)) + 1;x->height = max(height(x->left), height(x->right)) + 1;return x;}//rr型调整BTNode* rr_rotate(BTNode* y) {BTNode *x = y->right;y->right = x->left;x->left = y;y->height = max(height(y->left), height(y->right)) + 1;x->height = max(height(x->left), height(x->right)) + 1;return x;}//判断平衡int getBalance(BTNode* N) {if (N == NULL)return0;return height(N->left) - height(N->right);}//插⼊结点&数据BTNode* insert(BTNode* node, int key) {if (node == NULL)return newNode(key);if (key < node->key)node->left = insert(node->left, key);else if (key > node->key)node->right = insert(node->right, key);elsereturn node;node->height = 1 + max(height(node->left), height(node->right)); int balance = getBalance(node);if (balance > 1 && key < node->left->key) //LL型return ll_rotate(node);if (balance < -1 && key > node->right->key) //RR型return rr_rotate(node);if (balance > 1 && key > node->left->key) { //LR型node->left = rr_rotate(node->left);return ll_rotate(node);}if (balance < -1 && key < node->right->key) { //RL型node->right = ll_rotate(node->right);return rr_rotate(node);return node;}//遍历void preOrder(struct Node *root) { if (root != NULL) {printf("%d ", root->key);preOrder(root->left);preOrder(root->right);}}int main() {BTNode *root = NULL;root = insert(root, 2);root = insert(root, 1);root = insert(root, 0);root = insert(root, 3);root = insert(root, 4);root = insert(root, 4);root = insert(root, 5);root = insert(root, 6);root = insert(root, 9);root = insert(root, 8);root = insert(root, 7);printf("前序遍历:");preOrder(root);return0;}。
数据结构第六章二叉树的应用教案
6.3 哈夫曼树
• • 最优树的定义 如何构造最优树
6.3.1 基本术语
路径和路径长度
若在一棵树中存在着一个结点序列 k1,k2,…,kj,使得ki是ki+1的 双亲(1≤i<j),则称此结点序列是 从k1到kj的路径从k1到kj所经过的 分支数称为这两点之间的路径长度
结点的权和带权路径长度
权 给结点赋上一个有某种意义 的实数,我们称为权。 带权路径长度 从根结点到该结点之间路径 长度与该结点上权的乘积。
23 设 key = 48
T
20 10 T 23 T 25
T T
30
T
40 35 T
bool Find(BTreeNode* T, ElemType& item) if(T==NULL) return false; //查找失败 else { if(item==T->data) { item=T->data; return true; } else if(item<T->data) //向左子树继续查找 return Find(T->left, item); else return Find(T->right, item); } //向右子树继续查找
ri r2i ri r2i 1
(小顶堆)
或
ri r2i ri r2i 1
(大顶堆)
12, 36, 27, 65, 40, 34, 98, 81, 73, 55, 49
是小顶堆
12, 36, 27, 65, 40, 14, 98, 81, 73, 55, 49
不是堆
子树上查找;
3)大于根结点的关键字,则继续在右
子树上查找。
高度平衡的二叉树
AVL( Addison-Velski and Landis )树 伸展树 红黑树
二叉搜索树性能分析
对于有 n 个关键码的集合,其关键码有 n! 种 不同排列,可构成不同二叉搜索树有 1 n C 2 n (棵)
n 1
{2, 1, 3} {1, 2, 3} {1, 3, 2} {2, 3, 1} {3, 1, 2} {3, 2, 1}
B
BRAຫໍສະໝຸດ AR中序序列:BL
B
BR
A
AR
注意:改组后
B
A
平衡度为 0
2)RR平衡旋转: 若在A的右子树的右子树上插入结点,使A的平衡
因子从-1增加至-2,需要进行一次逆时针旋转。
(以B为旋转轴)
A B A C
左单旋转 (RotateLeft )
+1
A
0
+2
A
+1
C C A
0
0
B h D h
(a)
C E
Double Rotations
Fig. 28-5 (a) Adding 70 to the tree in Fig. 28-2c destroys its balance; to restore the balance, perform both (b) a right rotation and (c) a left rotation.
h
B
E
h D h
(b)
E
h + 1
B
h
D h + h 1
(c)
如果在子树E中插入一个新结点,该子树高度增1导致 结点A的平衡因子变成+2,出现不平衡。 沿插入路径检查三个结点A、C和E。它们处于一条方 向为“\”的直线上,需要做左单旋转。 以结点C为旋转轴,让结点A反时针旋转。
简述二叉树的五种形态
简述二叉树的五种形态二叉树是一种常用的数据结构,它由节点组成,每个节点最多有两个子节点。
根据节点的分布情况,二叉树可以分为五种形态,分别是满二叉树、完全二叉树、平衡二叉树、搜索二叉树和线索二叉树。
一、满二叉树满二叉树是指除了叶子节点外,每个节点都有两个子节点的二叉树。
也就是说,满二叉树的所有层都是满的,并且最后一层的叶子节点都靠左排列。
满二叉树的节点数可以通过公式计算得到,假设树的高度为h,则节点数为2^h - 1。
满二叉树的特点是结构简单,查找速度快。
在满二叉树中,任意两个节点的路径长度都相同。
二、完全二叉树完全二叉树是指除了最后一层之外,其他层都是满的,并且最后一层的叶子节点都靠左排列的二叉树。
完全二叉树的特点是节点数较少,结构相对简单。
完全二叉树通常用数组来表示,因为它的节点之间的关系可以通过数组的下标来表示。
在完全二叉树中,任意一个节点的左子节点的下标为2i,右子节点的下标为2i+1。
三、平衡二叉树平衡二叉树是指左右子树的高度差不超过1的二叉树。
平衡二叉树的特点是查找、插入和删除的时间复杂度都为O(logn),其中n是节点的数量。
平衡二叉树的高度可以通过节点的平衡因子来计算,平衡因子定义为左子树的高度减去右子树的高度。
平衡因子的取值范围为-1、0和1,当平衡因子的绝对值大于1时,需要通过旋转操作来调整树的平衡性。
四、搜索二叉树搜索二叉树,也称为二叉搜索树或排序二叉树,是一种特殊的二叉树。
它的特点是对于树中的任意一个节点,其左子树中的所有节点都小于它,右子树中的所有节点都大于它。
搜索二叉树的中序遍历结果是一个递增的有序序列。
搜索二叉树的特点是可以快速地查找某个节点,时间复杂度为O(logn),其中n是节点的数量。
但是,如果搜索二叉树不平衡,即左子树或右子树过深,则会导致查找的时间复杂度退化为O(n)。
五、线索二叉树线索二叉树是对二叉树进行了优化的数据结构,它通过添加指向前驱和后继节点的线索,使得遍历操作更加高效。
数据结构树和二叉树知识点总结
数据结构树和二叉树知识点总结
1.树的概念:树是一种非线性的数据结构,由节点和边构成,每个节点只能有一个父节点,但可以有多个子节点。
2. 二叉树的概念:二叉树是一种特殊的树结构,每个节点最多只有两个子节点,一个是左子节点,一个是右子节点。
3. 二叉树的遍历:二叉树的遍历分为前序遍历、中序遍历和后序遍历三种方式。
前序遍历是先访问根节点,再访问左子树,最后访问右子树;中序遍历是先访问左子树,再访问根节点,最后访问右子树;后序遍历是先访问左子树,再访问右子树,最后访问根节点。
4. 二叉搜索树:二叉搜索树是一种特殊的二叉树,它满足左子树中所有节点的值均小于根节点的值,右子树中所有节点的值均大于根节点的值。
因此,二叉搜索树的中序遍历是一个有序序列。
5. 平衡二叉树:平衡二叉树是一种特殊的二叉搜索树,它的左子树和右子树的高度差不超过1。
平衡二叉树的插入和删除操作可以保证树的平衡性,从而提高树的查询效率。
6. 堆:堆是一种特殊的树结构,它分为最大堆和最小堆两种。
最大堆的每个节点的值都大于等于其子节点的值,最小堆的每个节点的值都小于等于其子节点的值。
堆常用于排序和优先队列。
7. Trie树:Trie树是一种特殊的树结构,它用于字符串的匹配和检索。
Trie树的每个节点代表一个字符串的前缀,从根节点到叶子节点的路径组成一个完整的字符串。
以上是数据结构树和二叉树的一些基本知识点总结,对于深入学
习数据结构和算法有很大的帮助。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
二叉排序树和平衡二叉树的判别 1引言 数据结构是软件工程的一门核心专业基础课程,在我们专业的课程体系中起着承上启下的作用,学好数据结构对于提高理论认知水平和实践能力有着极为重要的作用。学习数据结构的最终目的是为了获得求解问题的能力。对于现实世界中的问题,应该能从中抽象出一个适当的数据模型,该数学模型在计算机内部用相应的数据结构来表示,然后设计一个解此数学模型的算法,在进行编程调试,最后获得问题的解答。 本次课程设计的题目是对二叉排序树和平衡二叉树的扩展延伸应用。首先我们得建立一个二叉树,二叉树有顺序存储结构和链式存储结构两种存储结构,此次我选用的是二叉链表的存储结构。对于判断平衡二叉树,需要求出其每个叶子结点所在的层数,这里我采用的边遍历边求的方式,遍历采用的是先序遍历。二叉树的建立以及二叉排序树和平衡二叉树的判别中都用到了递归思想。
2需求分析
2.1在日常生活中,人们几乎每天都要进行“查找”工作。所谓“查找”即为
在一个含有众多的数据元素(或记录)的查找表中找出某个“特定的”数据元素(或记录),即关键字。
2.2本程序意为对一个已经建立的动态查找表——二叉树——判断其是否是二
叉排序树和平衡二叉树。 3数据结构设计
3.1抽象数据类型二叉树的定义如下:
ADT BinaryTree{ 3.1.1数据对象D:D是具有相同特性的数据元素的集合。
3.1.2数据关系R:
若D=NULL,则R=NULL,称BinaryTree为空的二叉树; 若D!=NULL,则R={H},H是如下的二元关系: 3.1.2.1在D中存在唯一的称为根的数据元素root,它在关系H下无前驱; 3.1.2.2若D-{root}!=NULL,则存在D-{root}={Dl,Dr},且Dl与Dr相交为空; 3.1.2.3若Dl!=NULL,则Dl中存在唯一的元素xl,属于H,且存在Dl上的关系Hl属于H;若Dr!=NULL,则Dr中存在唯一的元素xr,属于H,且存在Dr上的关系Hr属于H;H={,,Hl,Hr}; 3.1.2.4(Dl,{Hl})是一棵符合本定义的二叉树,称为根的左子树, (Dr,{Hr})是一棵符合本定义的二叉树,称为根的右子树。
3.2基本操作P:
InitBiTree(&T); 操作结果:构造空二叉树T。 CreateBiTree(&T,definition); 初始条件:definition给出二叉树T的定义。 操作结果:按definition构造二叉树T。 }ADT Tree //包含头文件 #include using namespace std; //数据结构 typedef struct Bitree { int w; struct Bitree *lchild; struct Bitree *rchild; }Bitree; //定义符号常量 const Max=100; //定义全局变量 Bitree * root;//根结点 int i;//计数 //自定义函数原型说明 void creat(Bitree *p);//创建二叉树 void Create(); void judgeBST(Bitree * root);//判断二叉排序树 void judge1(); void judgeAVL(Bitree * root,int count,int mark[]);//判断平衡//二叉树 void judge2(int mark[]);
4算法设计
4.1算法内容 // Note:Your choice is C++ IDE #include using namespace std; typedef struct Bitree { int w; struct Bitree *lchild; struct Bitree *rchild; }Bitree; const Max=100; Bitree *root; int i;//计数 //创建二叉树 void creat(Bitree *p) //按照树的先序遍历顺序输入数据,并且当结点的左右孩子不存在时输入0 { if(p!=0) { //左孩子 p->lchild=new Bitree; cout<<"请输入结点数据:"; cin>>p->lchild->w; if(p->lchild->w!=0)creat(p->lchild); else {Bitree *q=p->lchild;p->lchild=0;delete q;} //右孩子 p->rchild=new Bitree; cout<<"请输入结点数据:"; cin>>p->rchild->w; if(p->rchild->w!=0)creat(p->rchild); else {Bitree *q=p->rchild;p->rchild=0;delete q;} } } void Create() { root=new Bitree; //按照树的先序遍历顺序输入数据,并且当结点的左右孩子不存在时输入0 cout<<"请输入结点数据:"; cin>>root->w; if(root->w!=0)creat(root); else {Bitree *p=root;root=0;delete p;} } //下面两个函数为判断二叉树是否为二叉排序树 void judgeBST(Bitree *root) { Bitree *l,*r; if(root!=0) { if(i==0) { l=root->lchild; if(l!=NULL&&root->ww){i++;return;} judgeBST(l); if(i==0) {r=root->rchild; if(r!=NULL&&root->w>r->w){i++;return;} judgeBST(r);} } } } void judge1() { if(i==0)cout<<"是二叉排序树!"
4.2调试分析 整个程序分为三大块:建立二叉树、判断是否为二叉排序树、判断是否为平衡二叉树。
4.2.1建立时开始没有考虑二叉树为空的情况,并且没有注意不用的空间应释
放。经调整,已解决。 4.2.2判断二叉树是否为二叉排序树时,开始没注意到当结点为空时,是不能
进行权值的大小比较的。并且标志i一旦不为0即可不再进行比较了。 4.2.3二叉树是否为平衡二叉树时,应注意到只要mark[j]-mark[0]<-1和
mark[j]-mark[0]>1满足其一就可,所以应用或运算符。 4.2.4调试中数据的输入应充分考虑各种情况:二叉树为空;二叉树非空时,
既是二叉排序树又是平衡二叉树、是二叉排序树不是平衡二叉树、是平衡二叉树不是二叉排序树、既不是二叉排序树也不是平衡二叉树。这样就可以充分检验程序的正确性。
4.3调试结果 根据二叉树的先序遍历顺序输入结点,若结点不存在,输入结点数据0(或左右孩子不存在时,孩子结点数据输入0)
4.3.1请输入结点数据:0
是二叉排序树! 是平衡二叉树!
4.3.2请输入结点数据:4
请输入结点数据:3 请输入结点数据:2 请输入结点数据:0 请输入结点数据:0 请输入结点数据:0 请输入结点数据:1 请输入结点数据:0 请输入结点数据:0 不是二叉排序树! 是平衡二叉树!
4.3.3请输入结点数据:5
请输入结点数据:3 请输入结点数据:2