平衡二叉树操作演示
- 格式:doc
- 大小:149.50 KB
- 文档页数:19
平衡二叉树操作的演示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);}。
一、平衡二叉树的概念平衡二叉树(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结点的位置。
平衡二叉树实现代码平衡二叉树(Balanced Binary Tree),也叫 AVL 树,是一种特殊的二叉树,它的每个节点的左子树和右子树的高度差不超过1、当插入或删除一个节点后,如果导致树的不平衡,就通过旋转操作来恢复平衡。
下面是平衡二叉树的实现代码:```python#定义平衡二叉树的节点类class AVLNode:def __init__(self, key):self.key = keyself.left = Noneself.right = Noneself.height = 1#定义平衡二叉树类class AVLTree:def __init__(self):self.root = None#获取节点的高度def get_height(self, node):if node is None:return 0return node.height#计算平衡因子def get_balance(self, node):if node is None:return 0return self.get_height(node.left) -self.get_height(node.right)#左旋操作def left_rotate(self, z):y = z.rightT2 = y.lefty.left = zz.right = T2z.height = 1 + max(self.get_height(z.left), self.get_height(z.right))y.height = 1 + max(self.get_height(y.left), self.get_height(y.right))return y#右旋操作def right_rotate(self, z):y = z.leftT3 = y.righty.right = zz.left = T3z.height = 1 + max(self.get_height(z.left), self.get_height(z.right))y.height = 1 + max(self.get_height(y.left), self.get_height(y.right))return y#插入节点def insert(self, key):def insert_node(node, key):if node is None:return AVLNode(key)elif key < node.key:node.left = insert_node(node.left, key)else:node.right = insert_node(node.right, key)node.height = 1 + max(self.get_height(node.left), self.get_height(node.right))balance = self.get_balance(node)#如果节点不平衡,进行旋转操作来恢复平衡if balance > 1:if key < node.left.key:return self.right_rotate(node)else:node.left = self.left_rotate(node.left)return self.right_rotate(node)if balance < -1:if key > node.right.key:return self.left_rotate(node)else:node.right = self.right_rotate(node.right)return self.left_rotate(node)return nodeself.root = insert_node(self.root, key)#删除节点def delete(self, key):def delete_node(node, key):if node is None:return nodeelif key < node.key:node.left = delete_node(node.left, key) elif key > node.key:node.right = delete_node(node.right, key) else:if node.left is None:temp = node.rightnode = Nonereturn tempelif node.right is None:temp = node.leftnode = Nonereturn temptemp = self.get_min_value_node(node.right)node.key = temp.keynode.right = delete_node(node.right, temp.key)if node is None:return nodenode.height = 1 + max(self.get_height(node.left), self.get_height(node.right))balance = self.get_balance(node)#如果节点不平衡,进行旋转操作来恢复平衡if balance > 1:if self.get_balance(node.left) >= 0:return self.right_rotate(node)else:node.left = self.left_rotate(node.left)return self.right_rotate(node)if balance < -1:if self.get_balance(node.right) <= 0:return self.left_rotate(node)else:node.right = self.right_rotate(node.right)return self.left_rotate(node)return nodeself.root = delete_node(self.root, key) #获取以一些节点为根的子树中的最小值节点def get_min_value_node(self, node):if node is None or node.left is None: return nodereturn self.get_min_value_node(node.left) #中序遍历树def inorder_traversal(self):def inorder(node):if node is None:returninorder(node.left)print(node.key, end=" ")inorder(node.right)inorder(self.root)#测试代码if __name__ == '__main__':tree = AVLTreenodes = [50, 30, 70, 20, 40, 60, 80, 25, 10, 55]for node in nodes:tree.insert(node)print("平衡二叉树中序遍历结果:")tree.inorder_traversalprint("\n删除节点 40 后的平衡二叉树中序遍历结果:")tree.delete(40)tree.inorder_traversal```以上就是平衡二叉树的实现代码,代码中包含了平衡二叉树节点类的定义,以及插入节点、删除节点、左旋和右旋操作等方法的实现。
一颗平衡二叉树非叶结点平衡因子1
平衡二叉树是一种特殊的二叉树,它的左右子树的高度差不大于1。
平衡二叉树的出现是为了解决二叉查找树在频繁插入和删除节点时出现的不平衡问题,使得树的高度保持在O(logN)级别。
而平衡因子是指一颗节点的左右子树高度差,平衡因子等于1的平衡二叉树非叶结点是一种特殊的平衡二叉树。
平衡因子等于1的平衡二叉树非叶结点,是指该节点的左右子树高度相差1。
这种平衡二叉树的特点是,左右子树的高度差为1,且左右子树都是平衡二叉树。
这样一来,这种平衡因子等于1的平衡二叉树非叶结点就具有了一些特殊的性质。
首先,这种平衡因子等于1的平衡二叉树非叶结点,它的左右子树高度相差1,这表明左子树的高度和右子树的高度非常接近。
这种接近性质使得这种平衡因子等于1的平衡二叉树非叶结点能够更好
地平衡左右子树之间的权重,使得插入和删除操作更稳定,效率更高。
其次,这种平衡因子等于1的平衡二叉树非叶结点,它的左右子树都是平衡二叉树,这就意味着左右子树的高度差不大于1,且左右子树都是平衡的,这使得这种平衡因子等于1的平衡二叉树非叶结点具有更好的平衡性和更高的效率。
最后,这种平衡因子等于1的平衡二叉树非叶结点在平衡二叉树的操作中具有很重要的作用。
因为非叶结点是平衡二叉树中最重要的部分,它的平衡因子等于1能够更好地平衡左右子树之间的权重,防止因插入或删除节点而导致的树的不平衡。
总之,平衡因子等于1的平衡二叉树非叶结点是一种特殊的平衡二叉树。
它具有接近性质、平衡性和高效性,是平衡二叉树中最重要的部分。
在平衡二叉树的操作中,我们要注意维护它的平衡性,保证左右子树的平衡因子相差不大于1,以保证平衡二叉树的效率。
平衡二叉树调整算法在平衡二叉树中插入一个结点后造成不平衡,设最低的不平衡结点为A,并已知A的左孩子平衡因子为0,右孩子平衡因子为1,则应该做(C)型调整以使其平衡A LLB LRC RLD RR若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性。
首先要找出插入新结点后失去平衡的最小子树根结点的指针。
然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树。
当失去平衡的最小子树被调整为平衡子树后,原有其他所有不平衡子树无需调整,整个二叉排序树就又成为一棵平衡二叉树。
失去平衡的最小子树是指以离插入结点最近,且平衡因子绝对值大于 1 的结点作为根的子树。
假设用 A 表示失去平衡的最小子树的根结点,则调整该子树的操作可归纳为下列四种情况。
(1)LL型平衡旋转法由于在 A 的左孩子 B 的左子树上插入结点 F ,使 A 的平衡因子由 1 增至2 而失去平衡。
故需进行一次顺时针旋转操作。
即将 A 的左孩子 B 向右上旋转代替 A 作为根结点, A 向右下旋转成为 B 的右子树的根结点。
而原来B 的右子树则变成 A 的左子树。
(2)RR型平衡旋转法由于在 A 的右孩子 C 的右子树上插入结点 F ,使 A 的平衡因子由-1 减至-2 而失去平衡。
故需进行一次逆时针旋转操作。
即将 A 的右孩子 C 向左上旋转代替 A 作为根结点, A 向左下旋转成为 C 的左子树的根结点。
而原来C 的左子树则变成 A 的右子树。
(3)LR型平衡旋转法由于在 A 的左孩子 B 的右子数上插入结点 F ,使 A 的平衡因子由 1 增至2 而失去平衡。
故需进行两次旋转操作(先逆时针,后顺时针)。
即先将A 结点的左孩子B 的右子树的根结点 D 向左上旋转提升到 B 结点的位置,然后再把该D 结点向右上旋转提升到 A 结点的位置。
即先使之成为LL型,再按LL型处理。
如图中所示,即先将圆圈部分先调整为平衡树,然后将其以根结点接到 A 的左子树上,此时成为LL 型,再按LL 型处理成平衡型。
平衡二叉树介绍平衡二叉树(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. 任意节点到其每个叶子节点的路径上包含相同数目的黑色节点。
通过对节点进行颜色变换和旋转操作,红黑树可以在插入和删除节点的过程中保持平衡。
平衡二叉树的应用平衡二叉树在计算机科学中有广泛的应用。
数据结构课程设计(1)作业A一、大型作业(课程设计)题目和内容1.1二叉排序树与平衡二叉排序树基本操作的实现1.用二叉链表作储存结构(1)以回车(‘\n’)为输入结束标志,输入数列L,生成二叉排序树T;(2)对二叉排序树T作中序遍历,输出结果;(3)计算二叉排序树T的平均查找长度,输出结果;(4)输入元素x,查找二叉排序树T,如果存在含x的结点,则删除该结点,并作中序遍历(执行操作2);否则输出信息“无结点x”;(5)判断二叉排序树T是否为平衡二叉树,输出信息“OK!”/“NO!”;*(6)再用数列L,生成平衡二叉排序树BT:当插入新元素后,发现当前二叉排序树BT 不是平衡二叉排序树,则立即将它转换成新的平衡二叉排序树BT;*(7)计算平衡二叉排序树BT的平均查找长度,输出结果。
2、用顺序表(一维数组)作存储结构(1)以回车(‘\n’)为输入结束标志,输入数列L,生成二叉排序树T;(2)对二叉排序树T作中序遍历,输出结果;(3)计算二叉排序树T的平均查找长度,输出结果;(4)输入元素x,查找二叉排序树T,如果存在含x的结点,则删除该结点,并作中序遍历(执行操作2);否则输出信息“无结点x”;(5)判断二叉排序树T是否为平衡二叉树,输出信息“OK!”/“NO!”。
二. 程序中所采用的数据结构及存储结构的说明程序中的数据采用“树形结构”作为其数据结构。
具体的,我采用的是“二叉排序树”。
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:(1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;(2)若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;(3)它的左右子树也分别为二叉排序树。
程序中分别采用了“二插链表”和“一维数组”作为其存储结构。
二插链表存储结构中二插树的结点由一个数据元素和分别指向其左、右子树的两个分支构成。
如:我的程序中采用的结构是:typedef struct Tnode{int data;struct Tnode *lchild,*rchild;}*node,BSTnode;一维数组顺序表存储结构是用一组地址连续的存储单元依次自上而下、自左而右存储完全二插树上的结点元素,即将完全二叉树上编号为i的结点元素存储在如上定义的一维数组中下标为i-1的分量中。
算法(平衡⼆叉树)科普⼆叉树⼆叉树⼆叉数是每个节点最多有两个⼦树,或者是空树(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);}};...................................................................................................................############################################################################ ###################################################################################。
平衡二叉树构造过程1.插入操作:插入新节点是平衡二叉树构造过程中的基本操作之一、首先,将新节点插入到二叉树中的合适位置,然后检查树的平衡性。
在插入过程中,需要更新每个节点的高度,并验证是否需要进行旋转操作,以保持树的平衡。
具体插入操作的步骤如下:1.1在树中查找合适的位置插入新节点,按照二叉树的规则:-如果新节点值小于当前节点值,则继续在当前节点的左子树中查找合适位置插入新节点;-如果新节点值大于当前节点值,则继续在当前节点的右子树中查找合适位置插入新节点;-如果当前节点为空,则将新节点插入到此位置。
1.2更新每个节点的高度,从插入的节点开始,向上遍历到根节点。
计算每个节点的左子树高度和右子树高度,然后取其中较大值加1作为节点的新高度。
1.3验证平衡性。
对于每个节点,计算其左右子树高度差的绝对值,如果超过1,则需要进行旋转操作。
2.旋转操作:旋转是平衡二叉树构造过程中的关键步骤,用来调整树的结构,使其保持平衡。
2.1左旋:将当前节点的右子树变为新的根节点,当前节点成为新的根节点的左子树,新的根节点的左子树成为当前节点的右子树。
2.2右旋:将当前节点的左子树变为新的根节点,当前节点成为新的根节点的右子树,新的根节点的右子树成为当前节点的左子树。
2.3左右旋:先对当前节点的左子树进行左旋操作,然后再对当前节点进行右旋操作。
2.4右左旋:先对当前节点的右子树进行右旋操作,然后再对当前节点进行左旋操作。
旋转操作的目的是调整树的结构,使得左右子树的高度差不超过1,并保持二叉树的性质。
3.删除操作:删除节点是平衡二叉树构造过程中的另一个重要操作。
删除操作也需要更新树的高度和进行旋转操作。
删除操作的步骤如下:3.1在树中查找要删除的节点。
如果要删除的节点是叶子节点,则直接删除即可。
3.2如果要删除的节点只有一个子节点,则将子节点替换成当前节点的位置。
3.3如果要删除的节点有两个子节点,则找到当前节点的后继节点(即比当前节点大的最小节点)或前驱节点(即比当前节点小的最大节点),将后继节点或前驱节点的值复制到当前节点,并删除后继节点或前驱节点。
平衡二叉树的概念
平衡二叉树(Balanced Binary Tree),又称为AVL树,是一种特殊的二叉搜索树(Binary Search Tree)结构。
平衡二叉树的定义是:对于任意节点,其左子树和右子树的高度之差不超过1,并且左子树和右子树也都是平衡二叉树。
平衡二叉树的设计目的是为了解决普通二叉搜索树在插入、删除等操作时产生不平衡的问题,导致树的高度过高,从而影响搜索的效率。
通过保持树的平衡,平衡二叉树能够保证在最坏情况下的平均时间复杂度为O(log n),其中n是树中节点的数量。
为了保持平衡,平衡二叉树中的每个节点存储了额外的信息,通常是节点的高度。
当在平衡二叉树中插入或删除节点时,需要通过旋转操作来调整树的结构,以满足平衡条件。
旋转操作包括左旋和右旋,通过交换节点的位置来调整树的平衡。
平衡二叉树的应用非常广泛,特别是在需要高效地进行搜索、插入和删除操作的场景中,例如数据库和搜索引擎的索引结构、红黑树等。
通过保持树的平衡,平衡二叉树能够在较小的时间复杂度内完成这些操作,提高了数据结构的效率和性能。
#include<stdio.h>#include<malloc.h>typedef int KeyType; //定义关键字类型typedef struct node //记录类型{KeyType key; //关键字项int bf; //平衡因子struct node *lchild,*rchild; //左右孩子指针}BSTNode;void LeftProcess(BSTNode *&p,int &taller){//对以指针p所指结点为根的二叉树作左平衡旋转处理,本算法结束时,//指针p指向新的根结点BSTNode *p1,*p2;if(p->bf==0) //原本左右子树等高,现因左子树增高而使树增高{p->bf=1;taller=1;}else if(p->bf==-1) //原本右子树比左子树高,现左右子树等高{p->bf=0;taller=0;}else //原本左子树比右子树高,须作左子树的平衡处理{p1=p->lchild; //p指向*p的左子树根节点if(p1->bf==1) //新结点插入在*p的左孩子的左子树上,要做LL 调整{p->lchild=p1->rchild;p1->rchild=p;p->bf=p1->bf=0;p=p1;}else if(p1->bf==-1) //新结点插入在*p的左孩子的右子树上,要做LR调整{p2=p1->rchild;p1->rchild=p2->lchild;p2->lchild=p1;p->lchild=p2->rchild;p2->rchild=p;if(p2->bf==0) //新结点插入在*p2处作为叶子结点的情况p->bf=p1->bf=0;else if(p2->bf==1) //新结点插在*p2的左子树上的情况{p1->bf=0;p->bf=-1;}else //新结点插在*p2的右子树上的情况{p1->bf=1;p->bf=0;}p=p2;p->bf=0; //仍将p指向新的根结点,并置其bf值为0}taller=0;}}void RightProcess(BSTNode *&p,int &taller){//对以指针p所指结点为根的二叉树作右平衡旋转处理,本算法结束时,//指针p指向新的根结点BSTNode *p1,*p2;if(p->bf==0) //原本左右子树等高,现因右子树增高而使树增高{p->bf=-1;taller=1;}else if(p->bf==1) //原本左子树比右子树高,现左右子树等高{p->bf=0;taller=0;}else //原本右子树比左子树高,须作右子树的平衡处理{p1=p->rchild; //p指向*p的右子树根结点if(p1->bf==-1) //新结点插入在*p的右孩子的左子树上,要做RR 调整{p->rchild=p1->lchild;p1->lchild=p;p->bf=p1->bf=0;p=p1;}else if(p1->bf==1) //新结点插入在*p的右孩子的左子树上,要做RL 调整{p2=p1->lchild;p1->lchild=p2->rchild;p2->rchild=p1;p->rchild=p2->lchild;p2->lchild=p;if(p2->bf==0) //新结点插在*p2处作为叶子结点的情况p->bf=p1->bf=0;else if(p2->bf==-1) //新结点插在*p2的右子树上的情况{p1->bf=0;p->bf=1;}else //新结点插在*p2的左子树上的情况{p1->bf=-1;p->bf=0;}p=p2;p->bf=0; //仍将p指向新的结点,并置其bf值为0}taller=0;}}int InsertA VL(BSTNode*&b,KeyType e,int &taller){//若在平衡二叉排序树b中不存在和e有相同关键字的结点,则插入一个数据元素为e的新结点,//并返回1,否则返回0。
⼆叉查找树(BST)、平衡⼆叉树(AVL树)⼆叉查找树(BST) 特殊的⼆叉树,⼜称为排序⼆叉树、⼆叉搜索树、⼆叉排序树。
⼆叉查找树实际上是数据域有序的⼆叉树,即对树上的每个结点,都满⾜其左⼦树上所有结点的数据域均⼩于或等于根结点的数据域,右⼦树上所有结点的数据域均⼤于根结点的数据域。
如下图所⽰:⼆叉查找树通常包含查找、插⼊、建树和删除操作。
⼆叉查找树的创建对于⼀棵⼆叉查找树,其创建与⼆叉树的创建很类似,略有不同的是,⼆叉查找树,为了保证整棵树都关于根结点的⼤⼩呈左⼩右⼤的特征,在创建时,需要根据当前结点的⼤⼩来判断插⼊位置,给出如下代码:template<typename T>void BSTree<T>::createBSTreeByFile(ifstream &f){T e;queue<BSNode<T>*> q;while(!f.eof()){InputFromFile(f, e);Insert(root, e);}}template<typename T>void BSTree<T>::Insert(BSNode<T>* &t, T x){//得⽤指针的引⽤,不然传参时由于形参实例化,并不能成功创建⼆叉树if(t==NULL){t = new BSNode<T>;t->data = x;t->lchild = t->rchild = NULL;return;}if(x<=t->data){Insert(t->lchild, x);}else{Insert(t->rchild, x);}}⼆叉查找树的查找⼆叉查找树的查找有递归和⾮递归两种,对于递归⽅式,其递归边界为树的终⽌结点,⾮递归⽅式则采取对树中所有结点采取BFS或者DFS进⾏遍历的⽅式。
平衡二叉树的旋转操作平衡二叉树(AVL树)是一种自平衡的二叉搜索树,它的左子树和右子树的高度差(平衡因子)最多为1。
当插入或删除操作导致树的平衡被破坏时,需要进行旋转操作来恢复平衡。
本文将介绍平衡二叉树的旋转操作以及其实现原理。
1. 左旋操作左旋操作是一种将树向左偏移的操作,它可以用来处理右子树高度过高的情况。
具体步骤如下:(1). 将当前节点的右子节点作为新的根节点。
(2). 将新的根节点的左子节点作为当前节点的右子节点。
(3). 将当前节点作为新的根节点的左子节点。
左旋操作示意图如下:A B/ \ / \T1 B ---> A T3/ \ / \T2 T3 T1 T2在这个示例中,节点A的右子树过高,通过左旋操作将节点B作为新的根节点,节点A成为节点B的左子节点,节点T2成为节点A的右子节点。
2. 右旋操作右旋操作是一种将树向右偏移的操作,它可以用来处理左子树高度过高的情况。
具体步骤如下:(1). 将当前节点的左子节点作为新的根节点。
(2). 将新的根节点的右子节点作为当前节点的左子节点。
(3). 将当前节点作为新的根节点的右子节点。
右旋操作示意图如下:A C/ \ / \C T1 ---> T3 A/ \ / \T3 T2 T2 T1在这个示例中,节点A的左子树过高,通过右旋操作将节点C作为新的根节点,节点A成为节点C的右子节点,节点T2成为节点A的左子节点。
3. 左右旋和右左旋操作有时候仅通过单次旋转操作无法恢复平衡,需要进行左右旋或右左旋操作。
左右旋操作是先对当前节点的左子节点进行左旋,再对当前节点进行右旋。
右左旋操作是先对当前节点的右子节点进行右旋,再对当前节点进行左旋。
左右旋和右左旋操作的示意图如下:左右旋操作:A A C/ \ / \ / \B T4 --->C T4 ---> B A/ \ / \ / \ / \T1 C B T3 T1 T2 T3 T4/ \ / \T2 T3 T1 T2右左旋操作:A A B/ \ / \ / \T1 B ---> T1 C ---> A C/ \ / \ / \ / \C T4 T2 B T1 T2 T3 T4/ \ / \T2 T3 T3 T4通过左右旋和右左旋操作可以处理各种情况下的树平衡问题。
数据结构实习报告题目:平衡二叉树的操作演示班级:信息管理与信息系统11-1姓名:崔佳学号:3完成日期:2013.06.25一、需求分析1. 初始,平衡二叉树为空树,操作界面给出两棵平衡二叉树的显示、查找、插入、删除、销毁、合并两棵树,几种选择。
其中查找、插入和删除操作均要提示用户输入关键字。
每次插入或删除一个节点后都会更新平衡二叉树的显示。
2. 平衡二叉树的显示采用凹入表形式。
3.每次操作完毕后都会给出相应的操作结果,并进入下一次操作,知道用户选择退出二、概要设计1.平衡二叉树的抽象数据类型定义:ADT BalancedBinaryTree{数据对象D:D是具有相同特性的数据元素的集合。
各个数据元素均含有类型相同,可唯一标志的数据元素的关键字。
数据关系R:数据元素同属一个集合。
基本操作P:InitAVL(BSTree& T)操作结果:构造一个空的平衡二叉树TDestroyAVL(BSTree& T)初始条件:平衡二叉树T存在操作结果:销毁平衡二叉树TSearchAVL(BSTree T,int key)初始条件:平衡二叉树T存在,key为和关键字相同类型的给定值操作结果:若T中存在关键字和key相等的数据元素,则返回指向该元素的指针,否则为空InsertAVL(BSTree& T,int key,Status& taller)初始条件:平衡二叉树T存在,key和关键字的类型相同操作结果:若T中存在关键字等于key的数据元素则返回,若不存在则插入一个关键字为key的元素DeleteAVL(BSTree& T,int &key,Status& lower)初始条件:平衡二叉树T存在,key和关键字的类型相同操作结果:若T中存在关键字和key相同的数据元素则删除它}ADT BalancedBinaryTree2.本程序包含二个模块1)主程序模块:void main(){接收命令;While(“命令”!=“退出”){处理命令;清屏并得新打印提示信息;接收下一条命令;}}2)平衡二叉树基本操作实现平衡二叉树的抽象数据类型的各函数原型。
各模块之间的调用关系如下:主程序模块平衡二叉树模块三、详细设计1. 根据题目要求和平衡二叉树的操作特点,平衡二叉树采用整数链式存储结构基本操作的函数原型:#define LH 1 //左高#define EH 0 //等高#define RH -1 //右高#define TRUE 1#define FALSE 0#define ERROR 0#define OK 1typedef int Status;typedef int ElemType; //本程序处理数据对象为整型typedef struct BSTNode{ElemType data;int bf;struct BSTNode *lchild,*rchild;}BSTNode,*BSTree;1)平衡二叉树基本操作实现//构造平衡二叉树TStatus InitAVL(BSTree &T){T=NULL;return OK;}//对以*p为根的二叉树作左旋处理,处理之后p指向新的树根结点//即旋转处理之前的右子树的根结点void L_Rotate(BSTree &p){BSTree rc;rc=p->rchild;p->rchild=rc->lchild;rc->lchild=p; p=rc;}//对以*p为根的二叉树作右旋处理,处理之后p指向新的树根结点//即旋转处理之前的左子树的根结点void R_Rotate(BSTree &p){BSTree lc;lc=p->lchild;p->lchild=lc->rchild;lc->rchild=p; p=lc;}//对以指针T所指结点为根的二叉树作右平衡处理//本算法结束时T指向新的根结点void LeftBalance(BSTree &T){BSTree lc,rd;lc=T->lchild;switch(lc->bf){case LH:T->bf=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);}}//对以指针T所指结点为根的二叉树作右平衡处理//本算法结束时T指向新的根结点void RightBalance(BSTree& T){BSTree rc,rd;rc=T->rchild;switch(rc->bf){case RH: T->bf=rc->bf=EH;L_Rotate(T);break;case LH: rd=rc->lchild;switch(rd->bf){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; break;}rd->bf=EH;R_Rotate(T->rchild);L_Rotate(T);}}//查找关键字为key的结点//如有返回指向此结点的指针,如无返回空Status SearchAVL(BSTree T,int e){if(!T) return ERROR;if(T->data==e){printf("\t结果: %d[%d]\n\t",T->data,T->bf);return OK;}else{if(T->lchild)if(SearchAVL(T->lchild,e))return OK;if(T->rchild)if(SearchAVL(T->rchild,e))return OK;return ERROR;}}//若在平衡的二叉排序树中不存在和e相同的关键字的结点,则插入一个数据元素为e的新结点并返回1,否则返回0。
//若因插入而使二叉排序树失去平衡,则做平衡旋转处理//布尔变量taller反映T长高与否Status InsertAVL(BSTree &T,ElemType e,Status &taller){if(!T){T=(BSTree)malloc(sizeof(BSTNode));T->data=e;T->lchild=T->rchild=NULL;T->bf=EH;taller=TRUE;}else{if(e==T->data){taller=FALSE; return FALSE;}if(e<T->data){if(!InsertAVL(T->lchild,e,taller)) return FALSE;if(taller)switch(T->bf){case LH:LeftBalance(T); taller=FALSE; break;case EH:T->bf=LH; taller=TRUE; break;case RH:T->bf=EH; taller=FALSE; break;}}else{if(!InsertAVL(T->rchild,e,taller)) return FALSE;if(taller)switch(T->bf){case RH:RightBalance(T); taller=FALSE; break;case EH:T->bf=RH; taller=TRUE; break;case LH:T->bf=EH; taller=FALSE; break;}}}return TRUE;}//打印空格void Printblank(int i){while(i >=0){printf(" ");i--;}}//以凹入表的形式显示平衡二叉树Tvoid ViewTree(BSTree T,int i){if(T){ Printblank(i); printf("%d[%d]\n",T->data,T->bf);} else{ Printblank(i); printf("NULL\n"); return; }ViewTree(T->lchild,i+5);ViewTree(T->rchild,i+5);}//销毁平衡二叉树void DestroyAVL(BSTree &T){if(T){if(T->lchild)DestroyAVL(T->lchild);if(T->rchild)DestroyAVL(T->rchild);free(T);T=NULL;}}Status Delete(BSTree& p,int &e,int &flag){ BSTree q,s;if(!p->rchild){q=p;if(p->lchild){p->lchild->bf=p->bf;e=p->lchild->data;}p=p->lchild;free(q);flag=1;}else if(!p->lchild){q=p;p->rchild->bf=p->bf;e=p->rchild->data;p=p->rchild;free(q);flag=1;}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;else {q->lchild=s->lchild;p->bf=RH;}e=q->data;free(s);}return TRUE;}//若二叉排序树T中存在关键字等于e的数据元素时,则删除该数据元素结点//并返回TRUE,否则返回FALSEStatus DeleteBST(BSTree& T,int &e,int &flag){if(!T)return FALSE;else{if(e==T->data)return Delete(T,e,flag);else if(e<T->data) {if(!DeleteBST(T->lchild,e,flag)) return FALSE;return TRUE;}else {if(!DeleteBST(T->rchild,e,flag)) return FALSE;return TRUE;}}}void DelBalance(BSTree& T,int e, Status &lower,int &flag) {if(!T){lower=TRUE; return;}if(e==T->data){if(flag==1)switch(T->bf){case RH:case LH:T->bf=EH; lower=TRUE; break;}else switch(T->bf){case RH:lower=FALSE; break;case EH:T->bf=LH; lower=FALSE; break;case LH:LeftBalance(T); lower=TRUE; break;}return ;}if(e<T->data){DelBalance(T->lchild,e,lower,flag);if(lower)switch(T->bf){case LH:T->bf=EH; lower=TRUE; break;case EH:T->bf=RH; lower=FALSE; break;case RH:RightBalance(T); lower=TRUE; break;}}if(e>T->data){DelBalance(T->rchild,e,lower,flag);if(lower)switch(T->bf){case RH:T->bf=EH; lower=TRUE; break;case EH:T->bf=LH; lower=FALSE; break;case LH:LeftBalance(T); lower=TRUE; break;}}return ;}//删除平衡二叉树结点Status DeleteAVL(BSTree &T,int &e,Status &lower){ int flag=0;if(!DeleteBST(T,e,flag)) return FALSE;else DelBalance(T,e,lower,flag);return TRUE;}}2)主函数Main及其它辅助函数的实现/*主函数*/void main(){void Print();void About();BSTree T,t,p;int e,s; Status taller,lower;InitAVL(T);InitAVL(t);InitAVL(p);Print();scanf("%d",&s);while(s!=6){switch(s){case 1: //显示printf("按凹入表形式打印二叉树结构:\n");printf("T:\n");PrintTree(T,1);printf("t:\n");PrintTree(t,1);break;case 2: //查找printf("\t选择树(1,2):");scanf("%d",&s);printf("\t关键字(整数):");scanf("%d",&e);if(s==1) s=SearchAVL(T,e);if(s==2) s=SearchAVL(t,e);if(!s) printf("\t查找失败\n\t");break;case 3: //插入printf("\t选择树(1-T,2-t):");scanf("%d",&s);printf("\t关键字(整数):");scanf("%d",&e);if(s==1){InsertAVL(T,e,taller);printf("T:\n");PrintTree(T,1);}if(s==2){InsertAVL(t,e,taller);printf("t:\n");PrintTree(t,1);}break;case 4: //删除printf("\t选择树(1-T,2-t):");scanf("%d",&s);printf("\t关键字(整数):");scanf("%d",&e);if(s==1)if(DeleteAVL(T,e,lower))printf("\t删除成功\n\t");elseprintf("\t删除失败\n\t");if(s==2)if(DeleteAVL(t,e,lower))printf("\t删除成功\n\t");elseprintf("\t删除失败\n\t");break;case 5: //销毁printf("\t选择树(1,2):");scanf("%d",&s);if(s==1) DestroyAVL(T);if(s==2) DestroyAVL(t);printf("\t销毁成功\n\t");break;}system("pause");Print();scanf("%d",&s);}}void Print(){system("cls");printf(" ※※※※平衡二叉树操作演示※※※※\n");printf("\n");printf(" **************菜单**************** \n");printf(" * 1. 显示* \n");printf(" * 2. 查找* \n");printf(" * 3. 插入* \n");printf(" * 4. 删除* \n");printf(" * 5. 销毁* \n");printf(" * 6. 退出* \n");printf(" ********************************** \n");printf("请选择:\n");}3)函数之间的调用关系图:PrintTreeDelete四、调试分析1.本程序采用了凹表输出平衡二叉树各结点的关键字的值及平衡因子的值。