平衡二叉树和栈的运用
- 格式:doc
- 大小:231.00 KB
- 文档页数:26
平衡二叉树操作的演示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);}。
数据结构与算法系列研究五——树、⼆叉树、三叉树、平衡排序⼆叉树AVL树、⼆叉树、三叉树、平衡排序⼆叉树AVL⼀、树的定义树是计算机算法最重要的⾮线性结构。
树中每个数据元素⾄多有⼀个直接前驱,但可以有多个直接后继。
树是⼀种以分⽀关系定义的层次结构。
a.树是n(≥0)结点组成的有限集合。
{N.沃恩}(树是n(n≥1)个结点组成的有限集合。
{D.E.Knuth})在任意⼀棵⾮空树中:⑴有且仅有⼀个没有前驱的结点----根(root)。
⑵当n>1时,其余结点有且仅有⼀个直接前驱。
⑶所有结点都可以有0个或多个后继。
b. 树是n(n≥0)个结点组成的有限集合。
在任意⼀棵⾮空树中:⑴有⼀个特定的称为根(root)的结点。
⑵当n>1时,其余结点分为m(m≥0)个互不相交的⼦集T1,T2,…,Tm。
每个集合本⾝⼜是⼀棵树,并且称为根的⼦树(subtree)树的固有特性---递归性。
即⾮空树是由若⼲棵⼦树组成,⽽⼦树⼜可以由若⼲棵更⼩的⼦树组成。
树的基本操作1、InitTree(&T) 初始化2、DestroyTree(&T) 撤消树3、CreatTree(&T,F) 按F的定义⽣成树4、ClearTree(&T) 清除5、TreeEmpty(T) 判树空6、TreeDepth(T) 求树的深度7、Root(T) 返回根结点8、Parent(T,x) 返回结点 x 的双亲9、Child(T,x,i) 返回结点 x 的第i 个孩⼦10、InsertChild(&T,&p,i,x) 把 x 插⼊到 P的第i棵⼦树处11、DeleteChild(&T,&p,i) 删除结点P的第i棵⼦树12、traverse(T) 遍历树的结点:包含⼀个数据元素及若⼲指向⼦树的分⽀。
●结点的度: 结点拥有⼦树的数⽬●叶结点: 度为零的结点●分枝结点: 度⾮零的结点●树的度: 树中各结点度的最⼤值●孩⼦: 树中某个结点的⼦树的根●双亲: 结点的直接前驱●兄弟: 同⼀双亲的孩⼦互称兄弟●祖先: 从根结点到某结点j 路径上的所有结点(不包括指定结点)。
一、平衡二叉树的概念平衡二叉树(Balanced binary tree)是由阿德尔森-维尔斯和兰迪斯(Adelson-Velskii and Landis)于1962年首先提出的,所以又称为AVL树。
定义:平衡二叉树或为空树,或为如下性质的二叉排序树:(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的右子树。
(3)LR型平衡旋转法由于在A的左孩子B的右子数上插入结点F,使A的平衡因子由1增至2而失去平衡。
故需进行两次旋转操作(先逆时针,后顺时针)。
即先将A结点的左孩子B的右子树的根结点D向左上旋转提升到B结点的位置,然后再把该D结点向右上旋转提升到A结点的位置。
二叉树的储存结构的实现及应用二叉树是一种常见的数据结构,它在计算机科学和算法设计中广泛应用。
二叉树的储存结构有多种实现方式,包括顺序储存结构和链式储存结构。
本文将从这两种储存结构的实现和应用角度进行详细介绍,以便读者更好地理解二叉树的储存结构及其在实际应用中的作用。
一、顺序储存结构的实现及应用顺序储存结构是将二叉树的节点按照从上到下、从左到右的顺序依次存储在一维数组中。
通常采用数组来实现顺序储存结构,数组的下标和节点的位置之间存在一定的对应关系,通过数学计算可以快速找到节点的父节点、左孩子和右孩子。
顺序储存结构的实现相对简单,利用数组的特性可以迅速随机访问节点,适用于完全二叉树。
1.1 实现过程在采用顺序储存结构的实现中,需要首先确定二叉树的深度,然后根据深度确定数组的长度。
通过数学计算可以得到节点间的位置关系,初始化数组并按照规定的顺序将二叉树节点逐一填入数组中。
在访问二叉树节点时,可以通过计算得到节点的父节点和子节点的位置,从而实现随机访问。
1.2 应用场景顺序储存结构适用于完全二叉树的储存和遍历,常见的应用场景包括二叉堆和哈夫曼树。
二叉堆是一种特殊的二叉树,顺序储存结构可以方便地实现它的插入、删除和调整操作,因此在堆排序、优先队列等算法中得到广泛应用。
哈夫曼树则是数据压缩领域的重要应用,通过顺序储存结构可以有效地构建和处理哈夫曼树,实现压缩编码和解码操作。
二、链式储存结构的实现及应用链式储存结构是通过指针将二叉树的节点连接起来,形成一个类似链表的结构。
每个节点包含数据域和指针域,指针域指向节点的左右孩子节点。
链式储存结构的实现相对灵活,适用于任意形态的二叉树,但需要额外的指针空间来存储节点的地址信息。
2.1 实现过程在链式储存结构的实现中,每个节点需要定义为一个包含数据域和指针域的结构体或类。
通过指针来连接各个节点,形成一个二叉树的结构。
在树的遍历和操作中,可以通过指针的操作来实现节点的访问和处理,具有较高的灵活性和可扩展性。
平衡二叉树用途平衡二叉树是一种特殊的二叉树结构,它具有良好的平衡性,能够提高二叉树的查找、插入和删除操作的效率。
平衡二叉树在计算机科学领域中广泛应用,特别是在数据结构和算法中。
下面将详细介绍平衡二叉树的用途。
1. 提高查找效率平衡二叉树的一个重要应用是提高查找效率。
在平衡二叉树中,每个节点的左子树和右子树的高度差不超过1,这保证了树的高度相对较低。
相比于普通的二叉搜索树,平衡二叉树的查找操作更加高效。
在平衡二叉树中查找一个元素的平均时间复杂度为O(log n),而在普通二叉搜索树中,最坏情况下的时间复杂度为O(n)。
因此,平衡二叉树适用于需要频繁进行查找操作的场景,如数据库索引、字典等。
2. 支持有序遍历平衡二叉树具有有序性的特点,可以支持有序遍历。
有序遍历是指按照节点的值从小到大或从大到小的顺序遍历二叉树。
平衡二叉树可以通过中序遍历实现有序遍历,这对于需要按照顺序获取数据的应用场景非常有用,比如按照字母顺序输出单词列表、按照时间顺序输出事件列表等。
3. 实现高效的插入和删除操作平衡二叉树对于插入和删除操作也具有很好的效率。
在普通的二叉搜索树中,如果插入或删除一个节点后导致树的不平衡,就需要通过旋转操作来重新调整树的结构,以保持平衡。
而平衡二叉树在插入和删除操作时会自动进行平衡调整,不需要额外的旋转操作。
这使得平衡二叉树在插入和删除操作上具有更好的性能表现。
4. 提供高效的范围查询平衡二叉树支持范围查询,即根据给定的范围查找满足条件的元素。
通过中序遍历平衡二叉树,可以按照节点值的顺序获取元素,然后根据范围进行筛选。
这对于需要根据范围查询数据的应用场景非常有用,比如查找某个时间段内的日程安排、查找某个价格区间内的商品等。
5. 实现高效的集合操作平衡二叉树可以用来实现高效的集合操作,如并集、交集、差集等。
通过遍历两个平衡二叉树,可以将它们的元素按照一定的规则进行合并或筛选,从而实现集合操作。
这对于需要对大量数据进行集合操作的应用场景非常有用,比如数据去重、数据合并等。
二叉树用途二叉树是一种常用的数据结构,由节点和连接节点的边组成,其中每个节点最多有两个子节点,被称为左子节点和右子节点。
二叉树具有以下特点:1. 有层次结构:节点按照层次排列,每层从左到右。
2. 可以拥有零个、一个或两个子节点。
3. 二叉树的子树也是二叉树。
4. 深度为d的二叉树最多含有2^d-1个节点,其中d为二叉树的深度。
二叉树的用途非常广泛,下面将详细讨论几个主要的应用场景。
1. 搜索、排序和查找:二叉树可以用于快速搜索、排序和查找数据。
二叉搜索树是一种常用的二叉树类型,其中每个节点的值大于左子树的所有节点的值,小于右子树的所有节点的值。
通过二分查找算法,在二叉搜索树中可以快速定位目标值。
2. 堆:二叉堆是一种用于实现优先队列的数据结构。
它具有以下特点:任意节点的关键字值都小于(或大于)或等于其子节点的关键字值,根节点的关键字值最小(或最大);并且堆是一颗完全二叉树。
二叉堆的插入和删除操作的时间复杂度为O(log n),适用于一些需要高效的优先级操作的场景,例如任务调度。
3. 表达式树:二叉树可以用于存储和计算数学表达式。
表达式树是一种二叉树,其叶节点是操作数,内部节点是操作符。
通过遍历表达式树,我们可以通过递归的方式计算整个表达式的值。
4. 文件系统:二叉树可以用于组织和管理文件系统中的文件和文件夹。
每个节点代表一个文件或文件夹,左子节点代表文件夹下的子文件夹,右子节点代表同一层级下的其他文件或文件夹。
通过遍历二叉树,可以实现文件的查找、创建、删除等操作。
5. 数据压缩:哈夫曼树是一种常用的数据压缩算法,通过构建二叉树来实现。
在哈夫曼树中,出现频率较高的字符对应的节点位于树的较低层,而出现频率较低的字符对应的节点位于树的较高层。
通过对字符进行编码,并使用相对较短的编码表示高频字符,可以实现对数据的高效压缩和解压缩。
6. 平衡树:平衡树是一种特殊类型的二叉树,其左子树和右子树的高度差不超过1。
二叉树的现实中典型例子二叉树是一种常用的数据结构,它具有广泛的应用。
下面列举了十个二叉树在现实中的典型例子。
一、文件系统文件系统是计算机中常见的二叉树应用之一。
文件系统中的目录和文件可以组织成一棵树,每个目录称为一个节点,而文件则是叶子节点。
通过树的结构,我们可以方便地对文件和目录进行管理和查找。
二、组织架构企业或组织的组织架构通常可以用二叉树来表示。
每个部门可以看作是一个节点,而员工则是叶子节点。
通过组织架构树,我们可以清晰地了解到企业或组织内部的管理层级关系。
三、家谱家谱是一个家族的血缘关系的记录,一般可以用二叉树来表示。
每个人可以看作是一个节点,而父子关系则是节点之间的连接。
通过家谱树,我们可以追溯家族的历史和血缘关系。
四、编译器编译器是将高级语言转换为机器语言的程序。
在编译过程中,编译器通常会使用语法分析树来表示源代码的结构。
语法分析树是一种特殊的二叉树,它将源代码表示为一个树状结构,方便进行语法分析和编译优化。
五、数据库索引数据库中的索引是一种用于提高数据查询效率的数据结构。
常见的索引结构包括B树和B+树,它们都是二叉树的变种。
通过索引树,数据库可以快速地定位到需要查询的数据,提高数据库的检索性能。
六、表达式求值在数学计算中,表达式求值是一项重要的任务。
通过使用二叉树,我们可以方便地表示和计算表达式。
二叉树的叶子节点可以是操作数,而内部节点可以是运算符。
通过遍历二叉树,我们可以按照正确的顺序对表达式进行求值。
七、电路设计在电路设计中,二叉树也有广泛的应用。
例如,我们可以使用二叉树来表示逻辑电路的结构,每个门电路可以看作是一个节点,而连接线则是节点之间的连接。
通过电路设计树,我们可以方便地进行电路的布线和优化。
八、图像处理图像处理是一项常见的计算机技术,而二叉树在图像处理中也有重要的应用。
例如,我们可以使用二叉树来表示图像的像素信息,每个像素可以看作是一个节点,而像素之间的关系则是节点之间的连接。
二叉树算法的应用领域
二叉树算法在计算机科学和相关领域中有广泛的应用。
以下是一些常见的应用领域:
1. 数据库系统:二叉树被广泛用于数据库系统中的索引结构,如二叉搜索树(Binary Search Tree,BST)和平衡二叉树(如AVL树、红黑树)等,以提高数据的检索效率。
2. 文件系统:用于文件系统的目录结构,如B树和B+树,能够高效地组织和管理文件系统中的数据。
3. 编译器:语法分析阶段使用语法树(也是一种树结构)来表示源代码的语法结构,其中二叉树是语法树的一种常见形式。
4. 网络路由:路由表中的路由信息通常使用树状结构,如二叉树,以便高效地搜索和决定数据包的路由。
5. 图形学:在计算机图形学中,二叉树可以用于场景图(Scene Graph)的表示,用于管理和渲染三维场景中的对象。
6. 人工智能:决策树是一种特殊的二叉树,广泛应用于机器学习和数据挖掘中的分类和决策问题。
7. 操作系统:进程调度和资源管理中可能使用树结构来组织和管理进程。
8. 游戏开发:在游戏中,空间分区树(如四叉树和八叉树)常用于加速空间查询和碰撞检测。
9. 密码学:Merkle树是一种二叉树结构,被广泛用于区块链中的交易验证和Merkle证明。
10. 网络和通信:Huffman编码树用于数据压缩,而霍夫曼解码树用于解压缩。
这只是二叉树算法应用的一小部分。
它们在计算机科学的各个领域中都发挥着关键的作用,提高了数据结构和算法的效率和性能。
147在计算机世界中,有各种各样的抽象数据结构,包括数组,队列,堆栈,链表等。
这些数据结构都可以转换到现实生活中的各种问题中去,以此能够高效的解决一些问题。
在这些数据结构中,被使用的较为广泛的无疑是树状结构。
本文就将详细介绍一下树状结构。
所谓树状结构,就是将信息存贮在节点之中,节点与节点之间用边链接起来的结构。
一颗二叉树由结点的有限集合组成。
这个集合可以由一个根节点和两个不相交的二叉树组成,这两颗二叉树分别成为这个根节点的左子树和右子树。
关于树状结构其他种类更多的结构介绍,我们将在下文中一一阐述。
树状结构在现实生活中的使用也相当广泛。
从计算机网络到数据库实现,树状结构无时无刻的在提高我们的工作效率。
本文也会介绍其在生活中的应用,以引发读者对计算机科学的兴趣。
1 二叉检索树我们首先介绍一下树状结构中最为简单也是最为常见的一种树:二叉检索树(Binary Search Tree)。
1.1 定义首先我们介绍一下二叉检索树,明确一下它的定义。
所谓二叉检索树,就是满足一下条件的一棵二叉树:任意一个结点,设其值为K,则该节点的左子树中任意一个结点的值都小于K;该结点右子树种任意一个结点的值都大于或等于K。
如图1所示。
同时,任意一个结点都有其深度,我们定义为根节点到该节点的路径长度。
而BST的高度就是最深深度加1。
1.2 二叉检索树的搜索对于一棵二叉检索树而言,其最重要的功能就是能够快速的找到某一个节点的值。
假设我们从根节点开始,在BST中检索K值。
如果根节点存储的值为K,则检索结束。
如果不是K,则必须检索树的更深一层。
BST检索的优势在于只需要检索两棵子树的其中之一。
如果K小于根节点的值,则只需要检索左子树,反之则检索右子树。
这个过程将会一直持续到K被找到,或者到一个叶节点(没有子树)为止。
如果到了一个叶节点,依然没有发现K,则表示K不在该BST中。
搜索所消耗的时间取决于该结点被找到的深度。
我们思考一下在一般的情况下,我们需要往下寻找直到一个最深叶节点才能够停下。
平衡⼆叉树详解平衡⼆叉树详解简介平衡⼆叉树(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;}。
数学与计算机学院课程设计说明书课程名称: 数据结构与算法A设计实践课程代码: 6015059题目一: 栈的应用1 题目二: 二叉排序树的实现年级/专业/班: 某年某月学生姓名: 某某人学号:开始时间: X 年 X月 X 日完成时间: X 年 X月X 日课程设计成绩:指导教师签名:年月目录摘要.................................................................. - 1 -1 引言.............................................................. - 2 -1.1任务与分析........................................................ - 2 -2 题目一的设计方案.................................................... - 2 -2.1整体设计方案...................................................... - 2 -2.2程序代码的编写与详细介绍.......................................... - 2 -2.3 程序演示......................................................... - 11 -3. 题目二的设计方案.................................................. - 12 -3.1整体设计方案..................................................... - 13 -3.2程序代码的编写与详细介绍......................................... - 13 -3.3程序演示......................................................... - 19 -结论............................................................... - 22 -致谢............................................................... - 23 -参考文献............................................................. - 24 -摘要数据结构是计算机存储、组织数据的方式。
是指相互之间存在一种或多种特定关系的数据元素的集合。
树型结构是一类重要的非线性数据结构,其中以树和二叉树最为常用。
关键词:数据结构,栈,顺序存储,链式存储,二叉排序树1 引言1.1任务与分析题目一:栈的应用1本题目的主要内容是实现了栈结构的基本操作。
具体要求是:(1)假设一死胡同仅能容一辆汽车进入,使用顺序栈模拟汽车进入和退出的动态过程;(2)使用链栈模拟以上问题;(3)验证用户输入的表达式是否符合数学意义上的括号匹配(常用的括号有( ( ), [ ] { } );题目二:二叉排序树的实现本题目的主要内容是实现了栈结构的基本操作。
具体要求是:(1)用顺序和二叉链表作存储结构,输入数列L,以回车('\n')为输入结束标志生成一棵二叉排序树T;(2)对二叉排序树T作中序和先序遍历,输出结果;(3)输入元素x,查找二叉排序树T,若存在含x的结点,则删除该结点,否则输出信息“无x”2 题目一的设计方案2.1整体设计方案建栈→车辆进站→车辆出战2.2程序代码的编写与详细介绍//用链栈模拟汽车进栈出栈//by hf 2014.5.31#include<stdio.h>#include<stdlib.h>#include<windows.h>#define TRUE 1#define FALSE 0#define NULL 0typedef int ElementType;typedef struct node //链栈结构体{ElementType data;struct node *next;}StackNode, *LinkStack;typedef struct stack //顺序栈的定义;{int a[100];int top;}Sqstack;void InitStack(LinkStack top);int IsEmpty(LinkStack top);int Push(LinkStack top, ElementType element);int Pop(LinkStack top, ElementType *element); Sqstack *InitStack1() //顺序栈的初始化;{Sqstack *ret=NULL;ret=(Sqstack *)malloc(sizeof(Sqstack));if(ret){ret->top=0;}return ret;}void InitStack(LinkStack top) //栈顶元素初始化{top->next = NULL;}int IsEmpty(LinkStack top) //判断栈顶元素是否为空{if(top->next == NULL){return TRUE;}else{return FALSE;}}int Push1(Sqstack *stack,int data)//进栈函数{stack->a[stack->top]=data;stack->top++;return 1;}int Pop1(Sqstack *stack,int data)//出栈函数{if(stack->top==0){puts("站内已经没有车了!");}else{data=stack->a[stack->top];stack->top--;}return 1;}int Push(LinkStack top, ElementType element) //车辆进站{StackNode *temp;temp = (StackNode *)malloc(sizeof(StackNode));if(temp == NULL){printf("\n我们车库太小了,不好意思你请到别处停车区吧...");return FALSE;}temp->data = element;temp->next = top->next;top->next = temp;return TRUE;}int Pop(LinkStack top, ElementType *element) //车辆出栈{if(IsEmpty(top)) {return FALSE;}StackNode *temp = top->next;*element = temp->data;top->next = temp->next;free(temp);return TRUE;}void Orderstack(){Sqstack *qq=InitStack1();puts("请输入要进站的车辆数:\n");int num=0;scanf("%d",&num);for(int k=0;k<num;k++) //车辆进站循环{int t=Push1(qq,k);if(t==1){printf("第%d辆车进栈!\n",k+1);Sleep(2000);}else{printf("第%d辆车出状况了...");getchar();continue;}}int flag=0;FF:puts("\n是否让车辆出站(Y/N)?");fflush(stdin);char a;a=getchar();if(a=='n'||a=='N'){puts("请按任意键结束...");return;}else if(a=='y'||a=='Y'){for(int da=num;da>0;da--) //车辆出站循环{if(Pop1(qq,da)==1){printf("第%d辆车出站了!\n",da);Sleep(2000);}else{puts("出站混乱,造成交通事故,请按任意键退出...");getchar();exit(0);}}}else{if(flag>=5){puts("你实在是太犹豫了,我们下班了!请按任意键退出...");printf("%d",flag);fflush(stdin);getchar();return;}else{flag++;goto FF;}}system("pause");}void Linkstack(){LinkStack ss;ss = (LinkStack)malloc(sizeof(StackNode));InitStack(ss);puts("请输入要进站的车辆数:\n");int m=0;scanf("%d",&m);if(m>0){for(int i=0;i<m;i++){if(Push(ss,i)==1){printf("\n第%d辆车已经进站!\n",i+1);Sleep(1000*2);}else{printf("\n第%d辆车好像违规了不能进站,请按任意键退出...",i+1);getchar();exit(0);}}}puts("\n所有车已经进站了哟...\n");Sleep(2000);int flag=0;KK:puts("\n是否让车辆出站(Y/N)?");fflush(stdin);char a;a=getchar();if(a=='n'||a=='N'){puts("请按任意键结束...");exit(0);}else if(a=='y'||a=='Y'){for(int j=0; j<m; j++){if(Push(ss,j)==1){printf("\n第%d辆车已经出站...\n",m-j);Sleep(2000);}else{puts("\n出站混乱,造成交通事故,请按任意键退出...");getchar();exit(0);}}puts("\n车辆已经全部出站了,请按任意键退出...");fflush(stdin);getchar();return;}else{if(flag>=5){puts("你实在是太犹豫了,我们下班了!请按任意键退出...");printf("%d",flag);fflush(stdin);getchar();return;}else{flag++;goto KK;}}system("pause");}int main(){system("cls");puts("********************请选择车辆进出栈方式***************************");puts("********************1.顺序进栈*************************************");puts("********************2.链式进栈*************************************");puts("********************3.退出系统*************************************");int k;puts("请输入你的选择:");scanf("%d",&k);if(k==1){Orderstack();}else if(k==2){Linkstack();}else if(k==3){exit(0);}else{main();}main();return 0;}表达式符号匹配://因用的结构是链式存储,就不在重复,主函数的调用如下//用链栈实现数学表达式括号匹配!//by hf 2014.5.31#include <stdio.h>#include <stdlib.h>#include <windows.h>#define TRUE 1#define FALSE 0#define NULL 0typedef char ElementType;typedef struct node {ElementType data;struct node *next;}StackNode, *LinkStack;void InitStack(LinkStack top) {top->next = NULL;}int IsEmpty(LinkStack top) {if(top->next == NULL) return TRUE;return FALSE;}int Push(LinkStack top, ElementType element) {StackNode *temp;temp = (StackNode *)malloc(sizeof(StackNode));if(temp == NULL) return FALSE;temp->data = element;temp->next = top->next;top->next = temp;return TRUE;}int Pop(LinkStack top, ElementType element) {if(IsEmpty(top)) return FALSE;StackNode *temp = top->next;element = temp->data;top->next = temp->next;free(temp);return TRUE;}ElementType GetTop(LinkStack top, ElementType element) { element = top->next->data;return element;}int main(){LinkStack s;s = (LinkStack)malloc(sizeof(StackNode));InitStack(s);puts("请输入一个数学表达试:\n");char a[1000];gets(a);puts("该表达试为:");puts(a);int i=0;while(a[i]!=NULL){if(a[i]=='('||a[i]=='{'||a[i]=='['||a[i]=='('){Push(s,a[i]);printf("括号:‘%c’正在匹配...\n",a[i]);Sleep(1000);}else if(a[i]==')'||a[i]=='}'||a[i]==']'||a[i]=='('){ElementType m[1];m[0]=GetTop(s,1);if(a[i]==')'&&m[0]=='('){Pop(s,a[i]);printf("括号:‘%c’已经被匹配到...\n",a[i]);Sleep(1000);}else if(a[i]==')'&&m[0]=='('){Pop(s,a[i]);printf("括号:‘%c’已经被匹配到...\n",a[i]);Sleep(1000);}else if(a[i]==']'&&m[0]=='['){Pop(s,a[i]);printf("括号:‘%c’已经被匹配到...\n",a[i]);Sleep(1000);}else if(a[i]=='}'&&m[0]=='{'){Pop(s,a[i]);printf("括号:‘%c’已经被匹配到...\n",a[i]);Sleep(1000);}else{printf("括号:‘%c’不能被被匹配到,表达式出错!!!\n",a[i]);Sleep(2000);puts("请按任意键退出...");getchar();exit(0);}}i++;}if(IsEmpty(s)==TRUE){puts("所有括号已经被匹配,表达式正确!");}else{ElementType m[1];m[0]=GetTop(s,1);printf("括号:‘%c’不能被被匹配到,表达式出错!!!\n",m[0]);Sleep(2000);puts("请按任意键退出...");getchar();exit(0);}system("pause");return 0;}2.3 程序演示基于顺序存储和链式存储的栈的操作是一样的,就简单地列举一种方式的运行情况,如图:根据给出的选择,进行操作表达式符号的匹配:3. 题目二的设计方案3.1整体设计方案此题基本是对于素组的一个存储,并且要求是有序的存储的。