数据结构C语言版 平衡二叉树

合集下载

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

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

平衡二叉树操作的演示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);}。

数据结构c语言课设-二叉树排序

数据结构c语言课设-二叉树排序

题目:二叉排序树的实现1 内容和要求1)编程实现二叉排序树,包括生成、插入,删除;2)对二叉排序树进展先根、中根、和后根非递归遍历;3)每次对树的修改操作和遍历操作的显示结果都需要在屏幕上用树的形状表示出来。

4)分别用二叉排序树和数组去存储一个班(50 人以上)的成员信息(至少包括学号、姓名、成绩3 项),比照查找效率,并说明在什么情况下二叉排序树效率高,为什么?2 解决方案和关键代码2.1 解决方案:先实现二叉排序树的生成、插入、删除,编写DisplayBST函数把遍历结果用树的形状表示出来。

前中后根遍历需要用到栈的数据构造,分模块编写栈与遍历代码。

要求比照二叉排序树和数组的查找效率,首先建立一个数组存储一个班的成员信息,分别用二叉树和数组查找,利用clock〔〕函数记录查找时间来比照查找效率。

2.2关键代码树的根本构造定义及根本函数typedef struct{KeyType key;} ElemType;typedef struct BiTNode//定义链表{ElemType data;struct BiTNode *lchild, *rchild;}BiTNode, *BiTree, *SElemType;//销毁树int DestroyBiTree(BiTree &T){if (T != NULL)free(T);return 0;}//清空树int ClearBiTree(BiTree &T){if (T != NULL){T->lchild = NULL;T->rchild = NULL;T = NULL;}return 0;}//查找关键字,指针p返回int SearchBST(BiTree T, KeyType key, BiTree f, BiTree &p) {if (!T){p = f;return FALSE;}else if EQ(key, T->data.key){p = T;return TRUE;}else if LT(key, T->data.key)return SearchBST(T->lchild, key, T, p);elsereturn SearchBST(T->rchild, key, T, p);}二叉树的生成、插入,删除生成void CreateBST(BiTree &BT, BiTree p){int i;ElemType k;printf("请输入元素值以创立排序二叉树:\n");scanf_s("%d", &k.key);for (i = 0; k.key != NULL; i++){//判断是否重复if (!SearchBST(BT, k.key, NULL, p)){InsertBST(BT, k);scanf_s("%d", &k.key);}else{printf("输入数据重复!\n");return;}}}插入int InsertBST(BiTree &T, ElemType e){BiTree s, p;if (!SearchBST(T, e.key, NULL, p)){s = (BiTree)malloc(sizeof(BiTNode));s->data = e;s->lchild = s->rchild = NULL;if (!p)T = s;else if LT(e.key, p->data.key)p->lchild = s;elsep->rchild = s;return TRUE;}else return FALSE;}删除//某个节点元素的删除int DeleteEle(BiTree &p){BiTree q, s;if (!p->rchild) //右子树为空{q = p;p = p->lchild;free(q);}else if (!p->lchild) //左子树为空{q = p;p = p->rchild;free(q);}else{q = p;s = p->lchild;while (s->rchild){q = s;s = s->rchild;}p->data = s->data;if (q != p)q->rchild = s->lchild;elseq->lchild = s->lchild;delete s;}return TRUE;}//整棵树的删除int DeleteBST(BiTree &T, KeyType key) //实现二叉排序树的删除操作{if (!T){return FALSE;}else{if (EQ(key, T->data.key)) //是否相等return DeleteEle(T);else if (LT(key, T->data.key)) //是否小于return DeleteBST(T->lchild, key);elsereturn DeleteBST(T->rchild, key);}return 0;}二叉树的前中后根遍历栈的定义typedef struct{SElemType *base;SElemType *top;int stacksize;}SqStack;int InitStack(SqStack &S) //构造空栈{S.base = (SElemType*)malloc(STACK_INIT_SIZE *sizeof(SElemType));if (!S.base) exit(OVERFLOW);S.top = S.base;S.stacksize = STACK_INIT_SIZE;return OK;}//InitStackint Push(SqStack &S, SElemType e) //插入元素e为新栈顶{if (S.top - S.base >= S.stacksize){S.base = (SElemType*)realloc(S.base, (S.stacksize + STACKINCREMENT)*sizeof(SElemType));if (!S.base) exit(OVERFLOW);S.top = S.base + S.stacksize;S.stacksize += STACKINCREMENT;}*S.top++ = e;return OK;}//Pushint Pop(SqStack &S, SElemType &e) //删除栈顶,应用e返回其值{if (S.top == S.base) return ERROR;e = *--S.top;return OK;}//Popint StackEmpty(SqStack S) //判断是否为空栈{if (S.base == S.top) return TRUE;return FALSE;}先根遍历int PreOrderTraverse(BiTree T, int(*Visit)(ElemType e)) {SqStack S;BiTree p;InitStack(S);p = T;while (p || !StackEmpty(S)){if (p){Push(S, p);if (!Visit(p->data)) return ERROR;p = p->lchild;}else{Pop(S, p);p = p->rchild;}}return OK;}中根遍历int InOrderTraverse(BiTree T, int(*Visit)(ElemType e)) {SqStack S;BiTree p;InitStack(S);p = T;while (p || !StackEmpty(S)){if (p){Push(S, p);p = p->lchild;}else{Pop(S, p);if (!Visit(p->data)) return ERROR;p = p->rchild;}}return OK;}后根遍历int PostOrderTraverse(BiTree T, int(*Visit)(ElemType e)) {SqStack S, SS;BiTree p;InitStack(S);InitStack(SS);p = T;while (p || !StackEmpty(S)){if (p){Push(S, p);Push(SS, p);p = p->rchild;}else{if (!StackEmpty(S)){Pop(S, p);p = p->lchild;}}}while (!StackEmpty(SS)){Pop(SS, p);if (!Visit(p->data)) return ERROR;}return OK;}利用数组存储一个班学生信息ElemType a[] = { 51, "陈继真", 88,82, "黄景元", 89,53, "贾成", 88,44, "呼颜", 90,25, "鲁修德", 88,56, "须成", 88,47, "孙祥", 87, 38, "柏有患", 89, 9, " 革高", 89, 10, "考鬲", 87, 31, "李燧", 86, 12, "夏祥", 89, 53, "余惠", 84, 4, "鲁芝", 90, 75, "黄丙庆", 88, 16, "李应", 89, 87, "杨志", 86, 18, "李逵", 89, 9, "阮小五", 85, 20, "史进", 88, 21, "秦明", 88, 82, "杨雄", 89, 23, "刘唐", 85, 64, "武松", 88, 25, "李俊", 88, 86, "卢俊义", 88, 27, "华荣", 87, 28, "杨胜", 88, 29, "林冲", 89, 70, "李跃", 85, 31, "蓝虎", 90, 32, "宋禄", 84, 73, "鲁智深", 89, 34, "关斌", 90, 55, "龚成", 87, 36, "黄乌", 87, 57, "孔道灵", 87, 38, "张焕", 84, 59, "李信", 88, 30, "徐山", 83, 41, "秦祥", 85, 42, "葛公", 85, 23, "武衍公", 87, 94, "范斌", 83, 45, "黄乌", 60, 67, "叶景昌", 99, 7, "焦龙", 89, 78, "星姚烨", 85, 49, "孙吉", 90, 60, "陈梦庚", 95,};数组查询函数void ArraySearch(ElemType a[], int key, int length){int i;for (i = 0; i <= length; i++){if (key == a[i].key){cout << "学号:" << a[i].key << " 姓名:" << a[i].name << " 成绩:" << a[i].grade << endl;break;}}}二叉树查询函数上文二叉树根本函数中的SearchBST()即为二叉树查询函数。

数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

数据结构与算法系列研究五——树、⼆叉树、三叉树、平衡排序⼆叉树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,这保证了树的高度相对较低。

相比于普通的二叉搜索树,平衡二叉树的查找操作更加高效。

在平衡二叉树中查找一个元素的平均时间复杂度为O(log n),而在普通二叉搜索树中,最坏情况下的时间复杂度为O(n)。

因此,平衡二叉树适用于需要频繁进行查找操作的场景,如数据库索引、字典等。

2. 支持有序遍历平衡二叉树具有有序性的特点,可以支持有序遍历。

有序遍历是指按照节点的值从小到大或从大到小的顺序遍历二叉树。

平衡二叉树可以通过中序遍历实现有序遍历,这对于需要按照顺序获取数据的应用场景非常有用,比如按照字母顺序输出单词列表、按照时间顺序输出事件列表等。

3. 实现高效的插入和删除操作平衡二叉树对于插入和删除操作也具有很好的效率。

在普通的二叉搜索树中,如果插入或删除一个节点后导致树的不平衡,就需要通过旋转操作来重新调整树的结构,以保持平衡。

而平衡二叉树在插入和删除操作时会自动进行平衡调整,不需要额外的旋转操作。

这使得平衡二叉树在插入和删除操作上具有更好的性能表现。

4. 提供高效的范围查询平衡二叉树支持范围查询,即根据给定的范围查找满足条件的元素。

通过中序遍历平衡二叉树,可以按照节点值的顺序获取元素,然后根据范围进行筛选。

这对于需要根据范围查询数据的应用场景非常有用,比如查找某个时间段内的日程安排、查找某个价格区间内的商品等。

5. 实现高效的集合操作平衡二叉树可以用来实现高效的集合操作,如并集、交集、差集等。

通过遍历两个平衡二叉树,可以将它们的元素按照一定的规则进行合并或筛选,从而实现集合操作。

这对于需要对大量数据进行集合操作的应用场景非常有用,比如数据去重、数据合并等。

二叉树c语言实现完整代码

二叉树c语言实现完整代码

二叉树c语言实现完整代码二叉树是一种非常常见的数据结构,它由节点和边组成,每个节点最多有两个子节点,分别称为左子节点和右子节点。

在计算机科学中,二叉树被广泛应用于搜索、排序、编译器等领域。

本文将介绍如何使用C语言实现二叉树的完整代码。

我们需要定义二叉树的节点结构体。

每个节点包含三个成员变量:数据、左子节点和右子节点。

代码如下:```struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;};```接下来,我们需要实现二叉树的基本操作,包括创建节点、插入节点、删除节点、查找节点等。

这些操作可以通过递归实现。

代码如下:```// 创建节点struct TreeNode* createNode(int val) {struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));node->val = val;node->left = NULL;node->right = NULL;return node;}// 插入节点struct TreeNode* insertNode(struct TreeNode* root, int val) {if (root == NULL) {return createNode(val);}if (val < root->val) {root->left = insertNode(root->left, val);} else {root->right = insertNode(root->right, val);}return root;}// 删除节点struct TreeNode* deleteNode(struct TreeNode* root, int val) {if (root == NULL) {return NULL;}if (val < root->val) {root->left = deleteNode(root->left, val);} else if (val > root->val) {root->right = deleteNode(root->right, val);} else {if (root->left == NULL) {struct TreeNode* temp = root->right;free(root);return temp;} else if (root->right == NULL) {struct TreeNode* temp = root->left;free(root);return temp;}struct TreeNode* temp = findMin(root->right); root->val = temp->val;root->right = deleteNode(root->right, temp->val); }return root;}// 查找节点struct TreeNode* searchNode(struct TreeNode* root, int val) {if (root == NULL || root->val == val) {return root;}if (val < root->val) {return searchNode(root->left, val);} else {return searchNode(root->right, val);}}// 查找最小节点struct TreeNode* findMin(struct TreeNode* root) {while (root->left != NULL) {root = root->left;}return root;}```我们需要实现二叉树的遍历操作,包括前序遍历、中序遍历和后序遍历。

数据结构-C语言-树和二叉树

数据结构-C语言-树和二叉树

练习
一棵完全二叉树有5000个结点,可以计算出其
叶结点的个数是( 2500)。
二叉树的性质和存储结构
性质4: 具有n个结点的完全二叉树的深度必为[log2n]+1
k-1层 k层
2k−1−1<n≤2k−1 或 2k−1≤n<2k n k−1≤log2n<k,因为k是整数
所以k = log2n + 1
遍历二叉树和线索二叉树
遍历定义
指按某条搜索路线遍访每个结点且不重复(又称周游)。
遍历用途
它是树结构插入、删除、修改、查找和排序运算的前提, 是二叉树一切运算的基础和核心。
遍历规则 D
先左后右
L
R
DLR LDR LRD DRL RDL RLD
遍历规则
A BC DE
先序遍历:A B D E C 中序遍历:D B E A C 后序遍历:D E B C A
练习 具有3个结点的二叉树可能有几种不同形态?普通树呢?
5种/2种
目 录 导 航 Contents
5.1 树和二叉树的定义 5.2 案例引入 5.3 树和二叉树的抽象数据类型定义 5.4 二叉树的性质和存储结构 5.5 遍历二叉树和线索二叉树 5.6 树和森林 5.7 哈夫曼树及其应用 5.8 案例分析与实现
(a + b *(c-d)-e/f)的二叉树
目 录 导 航 Contents
5.1 树和二叉树的定义 5.2 案例引入 5.3 树和二叉树的抽象数据类型定义 5.4 二叉树的性质和存储结构 5.5 遍历二叉树和线索二叉树 5.6 树和森林 5.7 哈夫曼树及其应用 5.8 案例分析与实现
二叉树的抽象数据类型定义
特殊形态的二叉树
只有最后一层叶子不满,且全部集中在左边

数据结构:第9章 查找2-二叉树和平衡二叉树

数据结构:第9章 查找2-二叉树和平衡二叉树
NODE *t; char x; {if(t==NULL)
return(NULL); else
{if(t->data==x) return(t);
if(x<(t->data) return(search(t->lchild,x));
else return(search(t->lchild,x)); } }
——这种既查找又插入的过程称为动态查找。 二叉排序树既有类似于折半查找的特性,又采用了链表存储, 它是动态查找表的一种适宜表示。
注:若数据元素的输入顺序不同,则得到的二叉排序树形态 也不同!
讨论1:二叉排序树的插入和查找操作 例:输入待查找的关键字序列=(45,24,53,45,12,24,90)
二叉排序树的建立 对于已给定一待排序的数据序列,通常采用逐步插入结点的方 法来构造二叉排序树,即只要反复调用二叉排序树的插入算法 即可,算法描述为: BiTree *Creat (int n) //建立含有n个结点的二叉排序树 { BiTree *BST= NULL;
for ( int i=1; i<=n; i++) { scanf(“%d”,&x); //输入关键字序列
– 法2:令*s代替*p
将S的左子树成为S的双亲Q的右子树,用S取代p 。 若C无右子树,用C取代p。
例:请从下面的二叉排序树中删除结点P。
F P
法1:
F
P
C
PR
C
PR
CL Q
CL QL
Q SL
S PR
QL S
SL
法2:
F
PS
C
PR
CL Q
QL SL S SL

平衡二叉树详解

平衡二叉树详解

平衡⼆叉树详解平衡⼆叉树详解简介平衡⼆叉树(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;}。

名词解释平衡二叉树

名词解释平衡二叉树

平衡二叉树介绍平衡二叉树(Balanced Binary Tree),简称AVL树,是一种特殊的二叉搜索树。

在平衡二叉树中,任意节点的左子树和右子树的高度之差不超过1。

这种平衡性的特点使得平衡二叉树的查找、插入和删除操作的时间复杂度保持在O(log n)级别,极大地提高了数据结构的效率。

定义和性质平衡二叉树是一种特殊的二叉搜索树,满足以下性质: 1. 空树或者任意节点的左右子树高度之差的绝对值不超过1。

2. 左子树和右子树都是平衡二叉树。

对于平衡二叉树,我们还可以得出一些重要的结论: 1. 平衡二叉树的任意节点的左子树和右子树的高度差不超过1。

也就是说,平衡二叉树的高度是一个较小的常数倍数。

2. 平衡二叉树的最小高度是log n,最大高度是2log n。

实现方法为了保持二叉树的平衡,我们需要对插入和删除操作进行适当的调整。

下面介绍两种常见的平衡二叉树实现方法。

AVL树AVL树是最早提出的平衡二叉树之一。

在AVL树中,每个节点都会存储一个额外的信息,即平衡因子(balance factor)。

平衡因子的定义是左子树的高度减去右子树的高度。

如果平衡因子的绝对值大于1,就需要进行平衡调整。

AVL树的平衡调整分为四种情况:左-左旋转(LL),右-右旋转(RR),左-右旋转(LR),和右-左旋转(RL)。

通过这四种旋转操作,可以使得树重新达到平衡状态。

红黑树红黑树是另一种常见的平衡二叉树。

红黑树的平衡调整是通过变换节点的颜色和旋转节点来完成的。

红黑树的规则如下: 1. 每个节点要么是红色,要么是黑色。

2. 根节点是黑色。

3. 所有叶子节点(NIL节点)都是黑色。

4. 如果一个节点是红色的,则它的两个子节点都是黑色的。

5. 任意节点到其每个叶子节点的路径上包含相同数目的黑色节点。

通过对节点进行颜色变换和旋转操作,红黑树可以在插入和删除节点的过程中保持平衡。

平衡二叉树的应用平衡二叉树在计算机科学中有广泛的应用。

二叉树 c语言

二叉树 c语言

二叉树 c语言在计算机科学领域中,树型数据结构是一种非常重要的数据结构,在实际开发中也得到了广泛的应用。

其中,二叉树又是一种非常常见的树型结构。

二叉树在很多情况下都能够提供更好的算法效率,同时也易于理解和实现,因此我们可以通过通过学习和掌握二叉树的特点以及优点,来更好的应用到实际开发中。

一、二叉树的定义二叉树是一种树型结构,树型结构是由节点构成的。

二叉树与一般的树型结构不同,它的每个节点最多只有两个子节点,分别称为左子树和右子树。

它们可以为空或者不为空,其子节点的数量时不固定且没有任何限制的。

二叉树的定义如下:(1)空树是树的一种特殊的状态。

我们可以把它称为二叉树;(2)若不是空树,那么它就是由一个称为根节点(root)的元素和左右两棵分别称为左子树(left subtree)和右子树(right subtree)的二叉树组成。

二、二叉树的特性(1)每个节点最多只有两个子节点,分别称为左子节点和右子节点;(2)左子树和右子树是二叉树;(3)二叉树没有重复的节点。

三、二叉树的应用二叉树是一种非常实用的数据结构,因为它可以模拟很多实际生活中的情况。

例如,我们可以利用二叉树来对某些数据进行分类和排序。

在二叉树的基础上,我们还可以构造二叉堆、哈夫曼树等更高级的数据结构。

除此之外,二叉树还可以应用到程序设计中。

例如,我们可以构造一个二叉树来表示某个程序的控制流,这个程序在执行时可以沿着二叉树的各个节点进行分支和选择,实现不同的功能。

此外,我们还可以利用二叉树来加快某些算法的执行效率,比如二分查找算法等。

四、二叉树的遍历方式对于二叉树的遍历,有三种基本方式,即前序遍历、中序遍历、后序遍历。

它们的遍历顺序不同,因此也得到了不同的称呼。

下面我们来简要介绍一下这三种遍历方式的特点和应用。

(1)前序遍历前序遍历是指首先访问树的根节点,然后按照从左到右的顺序依次遍历左子树和右子树。

前序遍历的应用非常广泛,可以用于生成表达式树、构造二叉树等等。

数据结构——用C语言描述 第六章 树状结构

数据结构——用C语言描述  第六章 树状结构

数据结构——用C语言描述第六章树状结构在计算机科学中,数据结构是组织和存储数据的方式,以便能够高效地访问和操作这些数据。

树状结构是一种重要的数据结构,它在许多算法和应用中都发挥着关键作用。

树状结构就像是一棵倒立的树,有一个根节点,然后从根节点向下延伸出许多分支,每个分支又可以进一步延伸出更多的分支。

这种结构使得数据的组织和管理更加清晰和高效。

在树状结构中,每个节点可以包含数据以及指向其子节点的指针。

节点之间通过这些指针形成层次关系。

树状结构的一个重要特点是,除了根节点外,每个节点都有且仅有一个父节点。

二叉树是树状结构中最常见的一种形式。

二叉树中的每个节点最多有两个子节点,分别称为左子节点和右子节点。

二叉搜索树是一种特殊的二叉树,它具有一定的规则。

对于二叉搜索树中的每个节点,其左子树中的所有节点的值都小于该节点的值,而其右子树中的所有节点的值都大于该节点的值。

这种特性使得在二叉搜索树中进行查找、插入和删除操作的效率很高。

例如,如果要在二叉搜索树中查找一个值,我们可以从根节点开始。

如果要查找的值小于当前节点的值,就向左子树继续查找;如果大于当前节点的值,就向右子树继续查找。

直到找到目标值或者确定该值不存在。

用 C 语言来实现二叉搜索树,首先需要定义一个节点结构体,来存储节点的数据以及左右子节点的指针。

```ctypedef struct TreeNode {int data;struct TreeNode left;struct TreeNode right;} TreeNode;```接下来,实现插入节点的函数。

插入节点时,需要按照二叉搜索树的规则,找到合适的位置插入新节点。

```cvoid insertNode(TreeNode root, int value) {if (root == NULL) {root =(TreeNode )malloc(sizeof(TreeNode));(root)>data = value;(root)>left = NULL;(root)>right = NULL;return;}if (value <(root)>data) {insertNode(&((root)>left), value);} else if (value >(root)>data) {insertNode(&((root)>right), value);}}```查找节点的函数也类似,根据比较值的大小在左右子树中递归查找。

算法(平衡二叉树)

算法(平衡二叉树)

算法(平衡⼆叉树)科普⼆叉树⼆叉树⼆叉数是每个节点最多有两个⼦树,或者是空树(n=0),或者是由⼀个根节点及两个互不相交的,分别称为左⼦树和右⼦树的⼆叉树组成满⼆叉树有两个⾮空⼦树(⼆叉树中的每个结点恰好有两个孩⼦结点切所有叶⼦结点都在同⼀层)也就是⼀个结点要么是叶结点,要么是有两个⼦结点的中间结点。

深度为k且含有2^k-1个结点的⼆叉树完全⼆叉树从左到右依次填充从根结点开始,依次从左到右填充树结点。

除最后⼀层外,每⼀层上的所有节点都有两个⼦节点,最后⼀层都是叶⼦节点。

平衡⼆叉树AVL树[3,1,2,5,9,7]⾸先科普下⼆叉排序树⼜称⼆叉查找树,议程⼆叉搜索树⼆叉排序树的规则⽐本⾝⼤放右边,⽐本⾝⼩放左边平衡⼆叉数⾸先是⼀个⼆叉排序树左右两个⼦树的⾼度差不⼤于1下⾯图中是平衡的情况下⾯是不平衡的情况引⼊公式(LL)右旋function toateRight(AvlNode){let node=AvlNode.left;//保存左节点 AvlNode.left=node.right;node.right=AvlNode;}(RR)左旋function roateLeft(AvlNode){let node=AvlNode.right;//保存右⼦节点AvlNode.right=node.left;node.left=AvlNode;return node;}左右旋⼤图判断⼆叉树是不是平衡树⼆叉树任意结点的左右⼦树的深度不超过1深度计算定义⼀个初始化的⼆叉树var nodes = {node: 6,left: {node: 5,left: {node: 4},right: {node: 3}},right: {node: 2,right: {node: 1}}}//计算⾼度const treeDepth = (root) => {if (root == null) {return 0;}let left = treeDepth(root.left)let right = treeDepth(root.right)return 1+(left>right?left:right)}//判断深度const isTree=(root)=>{if (root == null) {return true;}let left=treeDepth(root.left)let right=treeDepth(root.right)let diff=left-right;if (diff > 1 || diff < -1) {return false}return isTree(root.left)&&isTree(root.right) }console.log(isTree(nodes))判断⼆叉数是不是搜索⼆叉树//第⼀种 //中序遍历let last=-Infinity;const isValidBST=(root)=>{if (root == null) {return true;}//先从左节点开始if (isValidBST(root.left)) {if (last < root.node) {last=root.node;return isValidBST(root.right)}}return false}console.log(isValidBST(nodes))//第⼆种const isValidBST = root => {if (root == null) {return true}return dfs(root, -Infinity, Infinity)}const dfs = (root, min, max) => {if (root == null) {return true}if (root.node <= min || root.node >= max) {return false}return dfs(root.left, min, root.node) && dfs(root.right, root.node, max)}console.log(isValidBST(nodes))实现⼀个⼆叉树实现了⼆叉树的添加,删除,查找,排序//⼆叉树结点class TreeNode {constructor(n, left, right){this.n = n;this.left = left;this.right = right;}}//⼆叉树class BinaryTree {constructor(){this.length = 0;this.root = null;this.arr = [];}//添加对外⼊⼝,⾸个参数是数组,要求数组⾥都是数字,如果有不是数字则试图转成数字,如果有任何⼀个⽆法强制转成数字,则本操作⽆效 addNode(){let arr = arguments[0];if(arr.length == 0) return false;return this.judgeData('_addNode', arr)}//删除结点deleteNode(){let arr = arguments[0];if(arr.length == 0) return false;return this.judgeData('_deleteNode', arr)}//传值判断,如果全部正确,则全部加⼊叉树judgeData(func, arr){let flag = false;//任何⼀个⽆法转成数字,都会失败if(arr.every(n => !Number.isNaN(n))){let _this = this;arr.map(n => _this[func](n));flag = true;}return flag;}//添加的真实实现_addNode(n){n = Number(n);let current = this.root;let treeNode = new TreeNode(n, null, null);if(this.root === null){this.root = treeNode;}else {current = this.root;while(current){let parent = current;if(n < current.n){current = current.left;if(current === null){parent.left = treeNode;}}else {current = current.right;if(current === null){parent.right = treeNode;}}}}this.length++;return treeNode;}//删除节点的真实实现_deleteNode(n){n = Number(n);if(this.root === null){return;}//查找该节点,删除节点操作⽐较复杂,为排除找不到被删除的节点的情况,简化代码,先保证该节点是存在的,虽然这样做其实重复了⼀次查询了,但⼆叉树的查找效率很⾼,这是可接受的let deleteNode = this.findNode(n);if(!deleteNode){return;}//如果删除的是根节点if(deleteNode === this.root){if(this.root.left === null && this.root.right === null){this.root = null;}else if(this.root.left === null){this.root = this.root.right;}else if(this.root.right === null){this.root = this.root.left;}else {let [replaceNode, replacePNode, rp] = this.findLeftTreeMax(deleteNode);replacePNode[rp] = null;replaceNode.left = this.root.left;replaceNode.right = this.root.right;this.root = replaceNode;}}else {//被删除的⽗节点,⼦节点在⽗节点的位置p,有left,right两种可能let [deleteParent, p] = this.findParentNode(deleteNode);if(deleteNode.left === null && deleteNode.right === null){deleteParent[p] = null;}else if(deleteNode.left === null){deleteParent[p] = deleteNode.right;}else if(deleteNode.right === null){deleteParent[p] = deleteNode.left;}else {//⽤来替换被删除的节点,⽗节点,节点在⽗节点的位置let [replaceNode, replacePNode, rp] = this.findLeftTreeMax(deleteNode);if(replacePNode === deleteNode){deleteParent[p] = replaceNode;}else {deleteParent[p] = replaceNode;replacePNode.right = null;}replacePNode[rp] = null;replaceNode.left = deleteNode.left;replaceNode.right = deleteNode.right;}}this.length--;}//查找findNode(n){let result = null;let current = this.root;while(current){if(n === current.n){result = current;break;}else if(n < current.n){current = current.left;}else {current = current.right;}}return result;}//查找⽗节点findParentNode(node){let [parent, child, p] = [null, null, null];if(this.root !== node){parent = this.root;if(node.n < parent.n){child = parent.left;p = 'left';}else {child = parent.right;p = 'right';}while(child){if(node.n === child.n){break;}else if(node.n < child.n){parent = child;child = parent.left;p = 'left';}else {parent = child;child = parent.right;p = 'right';}}}return [parent, p];}//查找当前有左⼦树的节点的最⼤值的节点M,如有A个节点被删除,M是最接近A点之⼀(还有⼀个是右⼦树节点的最⼩值) findLeftTreeMax(topNode){let [node, parent, p] = [null, null, null];if(this.root === null || topNode.left === null){return [node, parent, p];}parent = topNode;node = topNode.left;p = 'left';while(node.right){parent = node;node = node.right;p = 'right';}return [node, parent, p];}//查找最⼤值maxValue(){if(this.root !== null){return this._findLimit('right');}}//查找最⼩值minValue(){if(this.root !== null){return this._findLimit('left');}}//实现查找特殊值_findLimit(pro){let n = this.root.n;let current = this.root;while(current[pro]){current = current[pro];n = current.n;}return n;}//中序排序,并⽤数组的形式显⽰sortMiddleToArr(){this._sortMiddleToArr(this.root);return this.arr;}//中序⽅法_sortMiddleToArr(node){if(node !== null){this._sortMiddleToArr(node.left);this.arr.push(node.n);this._sortMiddleToArr(node.right);}}//打印⼆叉树对象printNode(){console.log(JSON.parse(JSON.stringify(this.root)));}}//测试var binaryTree = new BinaryTree();binaryTree.addNode([50, 24, 18, 65, 4, 80, 75, 20, 37, 40, 60]);binaryTree.printNode();//{n: 50, left: {…}, right: {…}}console.log(binaryTree.maxValue());//80console.log(binaryTree.minValue());//4console.log(binaryTree.sortMiddleToArr());// [4, 18, 20, 24, 37, 40, 50, 60, 65, 75, 80] binaryTree.deleteNode([50]);binaryTree.printNode();//{n: 40, left: {…}, right: {…}}排序复习function ArrayList() {this.array = [];}ArrayList.prototype = {constructor: ArrayList,insert: function(item) {this.array.push(item);},toString: function() {return this.array.join();},swap: function(index1, index2) {var aux = this.array[index2];this.array[index2] = this.array[index1];this.array[index1] = aux;},//冒泡排序bubbleSort: function() {var length = this.array.length;for (var i = 0; i < length; i++) {for (var j = 0; j < length - 1 - i; j++) {if (this.array[j] > this.array[j + 1]) {this.swap(j, j + 1);}}}},//选择排序selectionSort: function() {var length = this.array.length;var indexMin;for (var i = 0; i < length - 1; i++) {indexMin = i;for (var j = i; j < length; j++) {if (this.array[indexMin] > this.array[j]) {indexMin = j;}}if (indexMin !== i) {this.swap(indexMin, i);}}},//插⼊排序insertionSort: function() {var length = this.array.length;var j;var temp;for (var i = 1; i < length; i++) {temp = this.array[i];j = i;while (j > 0 && this.array[j - 1] > temp) {this.array[j] = this.array[j - 1];j--;}this.array[j] = temp;}},//归并排序mergeSort: function() {function mergeSortRec(array) {var length = array.length;if (length === 1) {return array;}var mid = Math.floor(length / 2);var left = array.slice(0, mid);var right = array.slice(mid, length);return merge(mergeSortRec(left), mergeSortRec(right)); }function merge(left, right) {var result = [];var il = 0;var ir = 0;while (il < left.length && ir < right.length) {if (left[il] < right[ir]) {result.push(left[il++]);} else {result.push(right[ir++]);}}while (il < left.length) {result.push(left[il++]);}while (ir < right.length) {result.push(right[ir++]);}return result;}this.array = mergeSortRec(this.array);},//快速排序quickSort:function(){function sort(array){if (array.length <= 1) {return array;}var pivotIndex = Math.floor(array.length/2);var pivot = array.splice(pivotIndex,1)[0];var left = [];var right = [];for(var i = 0; i < array.length; i++){if (array[i] < pivot) {left.push(array[i]);}else{right.push(array[i]);}}return sort(left).concat([pivot],sort(right));}this.array = sort(this.array);}};...................................................................................................................############################################################################ ###################################################################################。

C语言二叉树的实际应用场景

C语言二叉树的实际应用场景

C语言二叉树的实际应用场景
树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很像自然界中的树那样。

树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都可用树形象表示。

树在计算机领域中也得到广泛应用,如在编译源程序如下时,可用树表示源程序如下的语法结构。

又如在数据库系统中,树型结构也是信息的重要组织形式之一。

一切具有层次关系的问题都可用树来描述。

分为满二叉树,完全二叉树,排序二叉树。

1、哈夫曼编码,来源于哈夫曼树【给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为赫夫曼树(Huffman tree)。

即带权路径长度最短的树】,在数据压缩上有重要应用,提高了传输的有效性,详见《信息论与编码》。

2、海量数据并发查询,二叉树复杂度是O(K+LgN)。

二叉排序树就既有链表的好处,也有数组的好处,在处理大批量的动态的数据是比较有用。

3、C++STL中的set/multiset、map,以及Linux虚拟内存的管理,都是通过红黑树去实现的。

查找最大(最小)的k个数,红黑树,红黑树中查找/删除/插入,都只需要O(logk)。

4、B-Tree,B+-Tree在文件系统中的目录应用。

5、路由器中的路由搜索引擎。

C语言数据结构系列篇二叉树的概念及满二叉树与完全二叉树

C语言数据结构系列篇二叉树的概念及满二叉树与完全二叉树

C语⾔数据结构系列篇⼆叉树的概念及满⼆叉树与完全⼆叉树链接:0x00 概念定义:⼆叉树既然叫⼆叉树,顾名思义即度最⼤为2的树称为⼆叉树。

它的度可以为 1 也可以为 0,但是度最⼤为 2 。

⼀颗⼆叉树是节点的⼀个有限集合,该集合:①由⼀个根节点加上两颗被称为左⼦树和右⼦树的⼆叉树组成②或者为空观察上图我们可以得出如下结论:①⼆叉树不存在度⼤于 2 的节点,换⾔之⼆叉树最多也只能有两个孩⼦。

②⼆叉树的⼦树有左右之分,分别为左孩⼦和右孩⼦。

次序不可颠倒,因此⼆叉树是有序树。

注意:对于任意的⼆叉树都是由以下⼏种情况复合⽽成的:0x01 满⼆叉树定义:⼀个⼆叉树,如果每⼀层的节点数都达到了最⼤值(均为2),则这个⼆叉树就可以被称作为 "满⼆叉树" 。

换⾔之,如果⼀个⼆叉树的层数为,且节点总数是,则他就是⼀个满⼆叉树。

计算公式:①已知层数求总数:②已知总数求层数:⼗亿个节点,满⼆叉树是多少层?≈ 10亿多0x02 完全⼆叉树定义:对于深度为的,有个结点的⼆叉树,当且仅当其每⼀个结点都与深度为的满⼆叉树中编号从 1 ⾄的结点⼀⼀对应时称之为完全⼆叉树。

前层是满的,最后⼀层不满,但是最后⼀层从左到右是连续的。

完全⼆叉树是效率很⾼的数据结构,完全⼆叉树是由满⼆叉树⽽引出来的。

所以,满⼆叉树是⼀种特殊的完全⼆叉树(每⼀层节点均为2)。

常识:①完全⼆叉树中,度为 1 的最多只有 1 个。

②⾼度为的完全⼆叉树节点范围是0x03 ⼆叉树的性质①若规定根节点的层数为 1 ,则⼀颗⾮空⼆叉树的第层上最多有个节点。

②若规定根节点的层数为 1 ,则深度为的⼆叉树最⼤节点数是 .③对任何⼀颗⼆叉树,如果度为 0 其叶⼦结点个数为,度为 2 的分⽀节点个数为,则有。

换⾔之,度为 0 的永远⽐度为 2 的多⼀个叶⼦结点。

④若规定根节点的层数为 1 ,具有个节点的满⼆叉树的深度(log是以2为底,n+1的对数)。

对于有个节点的完全⼆叉树,如果按照从上⾄下从左⾄右的数组顺序对所有节点从 0 开始编号,则对于序号为的节点有:(⾮完全⼆叉树,也可以⽤数组存放,但会浪费很多空间)假设是⽗节点在数组中的下标,此公式仅适⽤于完全⼆叉树:①求左孩⼦:②求右孩⼦:③求⽗亲(假设不关注是左孩⼦还是右孩⼦):④判断是否有左孩⼦:⑤判断是否由右孩⼦:PS:⼆叉树不⼀定要标准,⽐如这个其实也是⼆叉树:课后练习:1. 某⼆叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该⼆叉树中的叶⼦结点数为()A. 不存在这样的⼆叉树B. 200C. 1982. 在具有 2n 个结点的完全⼆叉树中,叶⼦结点个数为()A. nB. n+1C. n-1D. n/23. ⼀棵完全⼆叉树的节点数位为531个,那么这棵树的⾼度为()A. 11B. 10C. 8D. 125. ⼀个具有767个节点的完全⼆叉树,其叶⼦节点个数为()A. 383B. 384C. 385D. 386参考资料:Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .笔者:王亦优更新: 2021.11.24勘误:⽆声明:由于作者⽔平有限,本⽂有错误和不准确之处在所难免,本⼈也很想知道这些错误,恳望读者批评指正!本篇完。

课题_一步一步写平衡二叉树(AVL树)

课题_一步一步写平衡二叉树(AVL树)

一步一步写平衡二叉树(AVL树)平衡二叉树(Balanced Binary Tree)是二叉查找树的一个进化体,也是第一个引入平衡概念的二叉树。

1962年,G.M. Adelson-Velsky 和 E.M. Landis发明了这棵树,所以它又叫AVL树。

平衡二叉树要求对于每一个节点来说,它的左右子树的高度之差不能超过1,如果插入或者删除一个节点使得高度之差大于1,就要进行节点之间的旋转,将二叉树重新维持在一个平衡状态。

这个方案很好的解决了二叉查找树退化成链表的问题,把插入、查找、删除的时间复杂度最好情况和最坏情况都维持在O(logN)。

但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。

平衡二叉树实现的大部分过程和二叉查找树是一样的(学平衡二叉树之前一定要会二叉查找树),区别就在于插入和删除之后要写一个旋转算法去维持平衡,维持平衡需要借助一个节点高度的属性。

我参考了机械工业出版社的《数据结构与算法分析- C语言描述》写了一个C++版的代码。

这本书的AVLTree讲的很好,不过没有很完整的去描述。

我会一步一步的讲解如何写平衡二叉树,重点是平衡二叉树的核心部分,也就是旋转算法。

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

代码如下://AVL树节点信息template<class T>class TreeNode{public:TreeNode():lson(NULL),rson(NULL),freq(1),hgt(0){}T data;//值int hgt;//以此节点为根的树的高度unsigned int freq;//频率TreeNode* lson;//指向左儿子的地址TreeNode* rson;//指向右儿子的地址};第二步:平衡二叉树(AVL)类的声明声明中的旋转函数将在后边的步骤中详解。

数据结构_第9章_查找2-二叉树和平衡二叉树

数据结构_第9章_查找2-二叉树和平衡二叉树

F
PS
C
PR
CL Q
QL SL S SL
10
3
18
2
6 12
6 删除10
3
18
2
4 12
4
15
15
三、二叉排序树的查找分析
1) 二叉排序树上查找某关键字等于给定值的结点过程,其实 就是走了一条从根到该结点的路径。 比较的关键字次数=此结点的层次数; 最多的比较次数=树的深度(或高度),即 log2 n+1
-0 1 24
0 37
0 37
-0 1
需要RL平衡旋转 (绕C先顺后逆)
24
0
-012
13
3573
0
01
37
90
0 53 0 53
0 90
作业
已知如下所示长度为12的表:
(Jan, Feb, Mar, Apr, May, June, July, Aug, Sep, Oct, Nov, Dec)
(1) 试按表中元素的顺序依次插入一棵初始为空的二叉 排序树,画出插入完成之后的二叉排序树,并求其在 等概率的情况下查找成功的平均查找长度。
2) 一棵二叉排序树的平均查找长度为:
n i1
ASL 1
ni Ci
m
其中:
ni 是每层结点个数; Ci 是结点所在层次数; m 为树深。
最坏情况:即插入的n个元素从一开始就有序, ——变成单支树的形态!
此时树的深度为n ; ASL= (n+1)/2 此时查找效率与顺序查找情况相同。
最好情况:即:与折半查找中的判ห้องสมุดไป่ตู้树相同(形态比较均衡) 树的深度为:log 2n +1 ; ASL=log 2(n+1) –1 ;与折半查找相同。

c语言将二叉树填充为完全二叉树的方法

c语言将二叉树填充为完全二叉树的方法

c语言将二叉树填充为完全二叉树的方法要将二叉树填充为完全二叉树,需要按照层次遍历方式进行操作。

下面是使用C语言来实现这个过程的方法:#include <stdio.h>#include <stdlib.h>#define MAX_SIZE 100// 二叉树节点结构体typedef struct Node {int data; // 当前节点的数据struct Node* left; // 左子节点指针struct Node* right; // 右子节点指针} Node;// 辅助队列结构体typedef struct Queue {Node* data[MAX_SIZE];int front, rear;} Queue;// 创建新节点Node* createNode(int data) {Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data;newNode->left = NULL;newNode->right = NULL;return newNode;}// 插入节点Node* insertNode(Node* root, int data) {if (root == NULL) {return createNode(data);}Queue queue;queue.front = -1;queue.rear = -1;queue.data[++queue.rear] = root;while (queue.front != queue.rear) {Node* temp = queue.data[++queue.front];if (temp->left) {queue.data[++queue.rear] = temp->left; } else {temp->left = createNode(data);return root;}if (temp->right) {queue.data[++queue.rear] = temp->right; } else {temp->right = createNode(data);return root;}}return root;}// 中序遍历打印二叉树void inorderTraversal(Node* root) {if (root == NULL) {return;}inorderTraversal(root->left);printf("%d ", root->data);inorderTraversal(root->right);}int main() {Node* root = createNode(1);// 假设以下数据为二叉树的节点数据int data[] = {2, 3, 4, 5, 6, 7};int dataSize = sizeof(data) / sizeof(data[0]);for (int i = 0; i < dataSize; i++) {root = insertNode(root, data[i]);}printf("填充完全二叉树后的中序遍历结果:");inorderTraversal(root);return 0;}通过以上代码,我们可以将给定的二叉树填充为完全二叉树,并通过中序遍历方式打印出填充完后的结果。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

/*数据结构C语言版平衡二叉树P236编译环境:Dev-C++ 4.9.9.2日期:2011年2月15日*/#include <stdio.h>#include <malloc.h>#define LH +1 // 左高#define EH 0 // 等高#define RH -1 // 右高#define N 5 // 数据元素个数typedef char KeyType; // 设关键字域为字符型typedef struct{KeyType key;int order;}ElemType; // 数据元素类型// 平衡二叉树的类型typedef struct BSTNode{ElemType data;// bf结点的平衡因子,只能够取0,-1,1,它是左子树的深度减去// 右子树的深度得到的int bf;struct BSTNode *lchild,*rchild; // 左、右孩子指针}BSTNode,*BSTree;// 构造一个空的动态查找表DTint InitDSTable(BSTree *DT){*DT=NULL;return 1;}// 销毁动态查找表DTvoid DestroyDSTable(BSTree *DT){if(*DT) // 非空树{if((*DT)->lchild) // 有左孩子DestroyDSTable(&(*DT)->lchild); // 销毁左孩子子树if((*DT)->rchild) // 有右孩子DestroyDSTable(&(*DT)->rchild); // 销毁右孩子子树free(*DT); // 释放根结点*DT=NULL; // 空指针赋0}}// 算法9.5(a)// 在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素,// 若查找成功,则返回指向该数据元素结点的指针,否则返回空指针。

BSTree SearchBST(BSTree T,KeyType key){if((!T)|| (key == T->data.key))return T; // 查找结束else if(key < T->data.key) // 在左子树中继续查找return SearchBST(T->lchild,key);elsereturn SearchBST(T->rchild,key); // 在右子树中继续查找}// 算法9.9 P236// 对以*p为根的二叉排序树作右旋处理,处理之后p指向新的树根结点,即旋转// 处理之前的左子树的根结点。

void R_Rotate(BSTree *p){BSTree lc;lc=(*p)->lchild; // lc指向p的左子树根结点(*p)->lchild=lc->rchild; // lc的右子树挂接为p的左子树lc->rchild=*p;*p=lc; // p指向新的根结点}// 算法9.10 P236// 对以*p为根的二叉排序树作左旋处理,处理之后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指向新的根结点}// 算法9.12 P238// 对以指针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;}rd->bf=EH;L_Rotate(&(*T)->lchild); // 对*T的左子树作左旋平衡处理R_Rotate(T); // 对*T作右旋平衡处理}}// 对以指针T所指结点为根的二叉树作右平衡旋转处理,本算法结束时,// 指针T指向新的根结点void RightBalance(BSTree *T){BSTree rc,rd;rc=(*T)->rchild; // rc指向*T的右子树根结点switch(rc->bf){ // 检查*T的右子树的平衡度,并作相应平衡处理case RH: // 新结点插入在*T的右孩子的右子树上,要作单左旋处理(*T)->bf=rc->bf=EH;L_Rotate(T);break;case LH: // 新结点插入在*T的右孩子的左子树上,要作双旋处理rd=rc->lchild; // rd指向*T的右孩子的左子树根switch(rd->bf){ // 修改*T及其右孩子的平衡因子case RH: (*T)->bf=LH;rc->bf=EH;break;case EH: (*T)->bf=rc->bf=EH;break;case LH: (*T)->bf=EH;rc->bf=RH;}rd->bf=EH;R_Rotate(&(*T)->rchild); // 对*T的右子树作右旋平衡处理L_Rotate(T); // 对*T作左旋平衡处理}}// 算法9.11// 若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个// 数据元素为e的新结点,并返回1,否则返回0。

若因插入而使二叉排序树// 失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否。

int InsertAVL(BSTree *T,ElemType e,int *taller){if(!*T){ // 插入新结点,树“长高”,置taller为1*T=(BSTree)malloc(sizeof(BSTNode));(*T)->data=e;(*T)->lchild=(*T)->rchild=NULL;(*T)->bf=EH;*taller=1;}else{if(e.key == (*T)->data.key){ // 树中已存在和e有相同关键字的结点则不再插入*taller=0;return 0;}if(e.key < (*T)->data.key){ // 应继续在*T的左子树中进行搜索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; //标志没长高}}else{// 应继续在*T的右子树中进行搜索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;}}}return 1;}// 按关键字的顺序对DT的每个结点调用函数Visit()一次void TraverseDSTable(BSTree DT,void(*Visit)(ElemType)){if(DT){TraverseDSTable(DT->lchild,Visit); // 先中序遍历左子树Visit(DT->data); // 再访问根结点TraverseDSTable(DT->rchild,Visit); // 最后中序遍历右子树}}void print(ElemType c){printf("(%d,%d)",c.key,c.order);}int main(){BSTree dt,p;int k;int i;KeyType j;ElemType r[N]={{13,1},{24,2},{37,3},{90,4},{53,5}}; // (以教科书P234图9.12为例)InitDSTable(&dt); // 初始化空树for(i=0;i<N;i++)InsertAVL(&dt,r[i],&k); // 建平衡二叉树TraverseDSTable(dt,print); // 按关键字顺序遍历二叉树printf("\n请输入待查找的关键字: ");scanf("%d",&j);p=SearchBST(dt,j); // 查找给定关键字的记录if(p)print(p->data);elseprintf("表中不存在此值");printf("\n");DestroyDSTable(&dt);system("pause");return 0;}/*输出效果:(13,1)(24,2)(37,3)(53,5)(90,4) 请输入待查找的关键字: 53 (53,5)请按任意键继续. . .*/。

相关文档
最新文档