数据结构课设 - 平衡二叉树的演示

筅森魡賤 提交于 2020-02-03 23:55:26

平衡二叉树的演示
一、需求分析:
(1) 构建一个平衡二叉树并实现创建、插入、查找、删除、销毁等操作。每种操作均提示输入关键字。每次插入或删除一个结点后,更新平衡二叉树的显示。
(2) 平衡二叉树的显示采用凹入表现形式。
(3)输入的形式时数字,无论对功能的选择还是对数据的录入,都是以数字的形式进行输入,无需使用文件保存数据。 
(4) 输出的形式时在dos界面进行输出,一旦检测到错误的输入就会报错提示用户从新输入。
(5)程序所能达到的功能:
A:创建一颗非空平衡二叉树
B:向平衡二叉树中添加结点
C:从平衡二叉树中删除结点
D:在平衡二叉树中查找结点
E:销毁平衡二叉树
F:输出打印一棵平衡二叉树
G:合并两棵平衡二叉树
H:分裂一颗平衡二叉树

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h> 
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW 0
#define LH +1	//左子树比右子树高 
#define EH 0	//等高 
#define RH -1	//右子树比左子树高 
typedef int Status;
typedef int KeyType;
typedef struct{
	KeyType key;
}RcdType;
typedef struct BBSTNode{
	RcdType data;
	int bf;		//结点平衡因子
	struct BBSTNode *lchild,*rchild; 
}*BBSTree;		//平衡二叉树 

void CreatBBST(BBSTree &T);		//构建一棵二叉平衡树 
BBSTree SearchBBST(BBSTree T,KeyType Key);	//二叉平衡树非递归查找 
void R_Rotate(BBSTree &p);		//对最小失衡子树p作右旋调整
void L_Rotate(BBSTree &p);		//对最小失衡子树p作左旋调整
void LeftBalance(BBSTree &T);	//左平衡处理操作
void RightBalance(BBSTree &T);	//右平衡处理操作
Status InsertAVL(BBSTree &T,RcdType e,Status &taller);		//将e插入到二叉树
Status DeleteAVL(BBSTree &T,KeyType key,Status &shorter);	//删除值为key的结点
void MergeBBST(BBSTree &T1,BBSTree &T2);	//合并两棵二叉树
void Split(BBSTree T,KeyType e,BBSTree &T1,BBSTree &T2);	//分裂操作
void SplitBBST(BBSTree T,KeyType e,BBSTree &T1,BBSTree &T2);	//防止在将二叉树T分裂好之前改变了T1或T2 
void DestroyBBST(BBSTree &T);	//销毁树 
void PrintBBST(BBSTree &T,int lev);		//凹入表形式显示方法
int InsertMain(BBSTree &T,int taller);	//连续插入函数 
void Start(BBSTree &T1,BBSTree &T2);	//操作演示界面
int main();		//main函数 

void CreatBBST(BBSTree &T){
	//构建一棵二叉平衡树 
	int num = 0,i,taller = 0,temp;
	RcdType e;
	printf("输入结点个数:");
	if(scanf("%d",&num)==1){
		if(num>0){
			printf("请输入结点值\n");
			for(i = 0;i < num;i++){
				printf("第%d个结点的值:",i+1);
				temp = scanf("%d",&e.key);
				if(temp==1)
					InsertAVL(T,e,taller); 
				else{
					printf("请规范输入!\n");
					fflush(stdin);
					i--;
				}
			} 
			printf("构建成功!\n");
		}
		else
			printf("构建失败!\n");
	}
	else 
		printf("请规范输入!\n");
	fflush(stdin);
}
 
BBSTree SearchBBST(BBSTree T,KeyType Key){
	//二叉平衡树非递归查找 
	while(T!=NULL){
		if(T->data.key==Key)
			return T;		//成功 
		else if(T->data.key>Key)
			T = T->lchild;		//在左子树中继续查找  
		else 
			T = T->rchild;		//在右子树中继续查找 
	} 
	return NULL;		//失败 
}

void R_Rotate(BBSTree &p){
	//对最小失衡子树p作右旋调整
	BBSTree lc = p->lchild;		//lc指向p结点的左孩子 
	p->lchild = lc->rchild;		//lc结点的右子树置为p结点的左子树 
	lc->rchild = p;		//置原根结点为lc结点的右孩子 
	p = lc;		//p指向新的根结点 
} 

void L_Rotate(BBSTree &p){
	//对最小失衡子树p作左旋调整
	BBSTree rc = p->rchild;		//rc指向p结点的右孩子 
	p->rchild = rc->lchild;	 	//rc结点的左子树置为p结点的右子树 
	rc->lchild = p;		//置原根结点为rc结点的左孩子 
	p = rc;		//p指向新的根结点 
}

void LeftBalance(BBSTree &T){
	//左平衡处理操作
	BBSTree lc,rd;
	lc = T->lchild;		//lc指向T的左孩子
	switch(lc->bf){		//检查T的左子树的平衡因子,并作相应处理 
		case LH:		//LL型,需右旋调整 
			T->bf = lc->bf = EH;	R_Rotate(T);	break;
			//右旋后平衡因子等于0 
		case RH:		//新结点插入在T的左孩子的右子树上属于LR型,双旋处理
			rd = lc->rchild;
			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作右旋调整
			break; 
	}  
} 

void RightBalance(BBSTree &T){
	//右平衡处理操作
	BBSTree rc,ld;
	rc = T->rchild;		//lc指向T的右孩子
	switch(rc->bf){		//检查T的右子树的平衡因子,并作相应处理
		case RH:		//RR型,需左旋调整 
			T->bf = rc->bf = EH;	L_Rotate(T);	break;
		case LH:		//新结点插入在T的右孩子的左子树上属于RL型,双旋处理
			ld = rc->lchild;
			switch(ld->bf){		//修改T及其右孩子的平衡因子
				case LH: T->bf = EH;	rc->bf = RH;	break;
				case EH: T->bf = rc->bf = EH;	break;
				case RH: T->bf = LH;	rc->bf = EH;	break;
			}
			ld->bf = EH;
			R_Rotate(T->rchild);		//对T的右子树作右旋调整
			L_Rotate(T);				//对T作左旋调整
	}
}

Status InsertAVL(BBSTree &T,RcdType e,Status &taller){
	//将e插入到二叉树
	if(T==NULL){	//T为空,树长高
		T=(BBSTree)malloc(sizeof(BBSTNode));
		T->data = e;
		T->bf = EH;	T->lchild = NULL;	T->rchild = NULL;	taller = TRUE;
	} 
	else if(e.key==T->data.key){	//树中已经存在和e相等的结点 
		taller = FALSE;	
		return FALSE;	//未插入 
	}
	else if(e.key < T->data.key){	//插入到左子树
		if(FALSE==InsertAVL(T->lchild,e,taller))
			return FALSE;
		if(TRUE==taller){
			switch(T->bf){		//检查T的平衡因子
				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(FALSE==InsertAVL(T->rchild,e,taller))
			return FALSE;
		if(TRUE==taller){
			switch(T->bf){		//检查T的平衡因子
				case LH:	//原左高,变等高
			 		T->bf = EH;	taller = FALSE;	break; 
				case EH:	//原等高,变右高
			 		T->bf = RH;	taller = TRUE;	break; 
				case RH: 	//原右高,右平衡处理 
			 		RightBalance(T);	taller = FALSE;	break;
			} 
		} 
	}
	return TRUE;
} 

Status DeleteAVL(BBSTree &T,KeyType key,Status &shorter) {
	//删除值为key的结点
    if(T == NULL) 
		return FALSE;
    if(T->data.key == key) {
        BBSTree p = NULL;
        if(T->lchild == NULL) {	//被删结点的左子树为空
            p = T;
            T = T->rchild;	//直接将被删结点的右子树顶上 
            free(p);
            shorter = TRUE;	//树变矮 
        }
        else if(T->rchild == NULL) {	//被删结点的右子树为空
            p = T;
            T = T->lchild;
            free(p);
            shorter = TRUE;
        }
        else {	//被删结点左右子树都不为空
            p = T->lchild;
            while(p->rchild)	//找左子树的最大值,与删除结点交换数据
                p = p->rchild;
            T->data.key = p->data.key;
            DeleteAVL(T->lchild,p->data.key,shorter);	//删除被替换的结点 
            if(shorter) {	//如果树变矮,调整平衡因子 
                switch(T->bf) {
                    case LH:T->bf = EH; shorter = TRUE; break;
                    case EH:T->bf = RH; shorter = FALSE; break;
                    case RH:    //删除的结点在左子树,如果本来是右高,右旋 
                        RightBalance(T);	break;
                }   
            }   
        }
    }
    else if(key < T->data.key) {	//在左子树中查找
        if(FALSE == DeleteAVL(T->lchild,key,shorter)) 
		 	return FALSE;
        if(shorter) {	//在左子树中删除,如果树变矮 
            switch(T->bf) {
                case LH:T->bf = EH; shorter = TRUE; break;
                case EH:T->bf = RH; shorter = FALSE; break;
                case RH:  
                    RightBalance(T);	break;
            }
        } 
    }
    else {	//在右子树中查找 
        if(FALSE == DeleteAVL(T->rchild,key,shorter)) 
			return FALSE;
        if(shorter) {	//在右子树中删除,如果树变矮 
            switch(T->bf) {
                case LH:  
                    LeftBalance(T);	break;
                case EH:T->bf = LH; shorter = FALSE; break;
                case RH:T->bf = EH; shorter = TRUE; break;                
            }
        }
    }
    return TRUE;
}    

void MergeBBST(BBSTree &T1,BBSTree &T2){
	//合并两棵二叉树
	int taller = 0;
	if(!T2)
		return;
	MergeBBST(T1,T2->lchild);
	InsertAVL(T1,T2->data,taller);
	MergeBBST(T1,T2->rchild);
	//中序遍历插入 
} 

//分裂一棵二叉树成为两棵 
void Split(BBSTree T,KeyType e,BBSTree &T1,BBSTree &T2){
	//分裂操作
	int taller = 0;
	if(!T)
		return ;
	Split(T->lchild,e,T1,T2);	//查找最左孩子 
	if(T->data.key > e)
		InsertAVL(T2,T->data,taller);
	else
		InsertAVL(T1,T->data,taller);
	Split(T->rchild,e,T1,T2);
	//中序遍历插入
} 
void SplitBBST(BBSTree T,KeyType e,BBSTree &T1,BBSTree &T2){
	//防止在将二叉树T分裂好之前改变了T1或T2 
	BBSTree t1 = NULL,t2 = NULL;
	Split(T,e,t1,t2);
	DestroyBBST(T1);
	DestroyBBST(T2);	//将之前的树先销毁 
	T1 = t1;
	T2 = t2;
}

void DestroyBBST(BBSTree &T){
	//销毁树 
	if(T==NULL)	return ;
	DestroyBBST(T->lchild);
	DestroyBBST(T->rchild);
	free(T);
}

void PrintBBST(BBSTree &T,int lev){
	//凹入表形式显示方法
	int i;
	if(T->rchild)
		PrintBBST(T->rchild,lev+1);
	for(i = 0;i < lev;i++)
		printf("  ");
	printf("%d\n",T->data.key);
	if(T->lchild)
		PrintBBST(T->lchild,lev+1);
}

int InsertMain(BBSTree &T,int taller){
	//连续插入函数 
	int n = 0;
	RcdType e;
	while(scanf("%d",&e.key)==1){
		if(InsertAVL(T,e,taller))
			n++;
	}
	fflush(stdin);
	return n;
} 

void Start(BBSTree &T1,BBSTree &T2){
	//操作演示界面 
	int cho=5,num,taller = 0,shorter = 0,temp;
	RcdType e;
	while(1){
		system("cls");
		printf("\n平衡二叉树操作的演示 \n");
		printf("***********************************************************\n");
		printf(" 平衡二叉树显示区 \n");
		printf("T1树\n\n");
		if(!T1)
			printf("当前为空树\n");
		else
			PrintBBST(T1,1);
		printf("\nT2树\n\n");
		if(!T2)
			printf(" 当前为空树\n");
		else
			PrintBBST(T2,1);
		printf("\n***********************************************************\n");
		printf("==========================================================\n");
		printf("| T1树操作:1.创建 2.插入 3.查找 4.删除 5.销毁  11.分裂  |\n");
		printf("| T2树操作:6.创建 7.插入 8.查找 9.删除 10.销毁 12.分裂  |\n");
		printf("| 特殊操作:13.合并T1,T2   0.退出                        |\n");
		printf("==========================================================\n");
		printf("输入你要进行的操作:");
		temp = scanf("%d",&cho);
		fflush(stdin);	//输入多个字符,如果不清除缓冲区,那么就会进入死循环! 
		if(temp!=1){	//输入操作不成功 
			printf("请规范输入!\n"); 
			printf("按任意键返回>>>\n");
			getch();	continue;
		}
		switch(cho){
			case 1: 
				if(T1)
					printf("树不为空!\n"); 
				else 
					CreatBBST(T1);
				break;
			case 2:
				printf("输入要插入的值(输入任意非数字字符结束插入):"); 
				if(num = InsertMain(T1,taller))
					printf("成功插入了%d个结点!\n",num);	
				else  
					printf("插入失败!\n");
				break;
			case 3:
				printf("请输入要查找关键字的值:");
				temp = scanf("%d",&e.key);
				fflush(stdin);
				if(temp==1){
					if(SearchBBST(T1,e.key))
						printf("查找成功!\n");
					else
						printf("查找失败!\n");
				}
				else 
					printf("请规范输入!\n");
				break;
			case 4:
				printf("请输入要删除关键字的值:");
				temp = scanf("%d",&e.key);
				fflush(stdin);
				if(temp==1){
					if(DeleteAVL(T1,e.key,shorter))
						printf("删除成功!\n");
					else
						printf("删除失败!\n");
				}
				else 
					printf("请规范输入!\n");
				break;
			case 5:
				DestroyBBST(T1);
				T1 = NULL;	break;
			case 6: 
				if(T2)
					printf("树不为空!\n"); 
				else 
					CreatBBST(T2);
				break;
			case 7:
				printf("入要插入的值(输入任意非数字字符结束插入):");
				if(num = InsertMain(T2,taller))
					printf("成功插入了%d个结点!\n",num);	
				else  
					printf("插入失败!\n");
				break;
			case 8:
				printf("请输入要查找关键字的值:");
				temp = scanf("%d",&e.key);
				fflush(stdin);
				if(temp==1){
					if(SearchBBST(T2,e.key))
						printf("查找成功!\n");
					else
						printf("查找失败!\n");
				}
				else 
					printf("请规范输入!\n");
				break;
			case 9:
				printf("请输入要删除关键字的值:");
				temp = scanf("%d",&e.key);
				fflush(stdin);
				if(temp==1){
					if(DeleteAVL(T2,e.key,shorter))
						printf("删除成功!\n");
					else
						printf("删除失败!\n");
				}
				else 
					printf("请规范输入!\n");
				break;
			case 10:
				DestroyBBST(T2);
				T2 = NULL;	break;
			case 11:
				if(T1){
					printf("请输入要分裂的中间值:");
					temp = scanf("%d",&e.key);
					fflush(stdin);
					if(temp==1)
						SplitBBST(T1,e.key,T1,T2);
					else
						printf("请规范输入!\n");
				}
				else 
					printf("树为空!\n");
				break;
			case 12:
				if(T2){
					printf("请输入要分裂的中间值:");
					temp = scanf("%d",&e.key);
					fflush(stdin);
					if(temp==1)
						SplitBBST(T2,e.key,T1,T2);
					else
						printf("请规范输入!\n");
				}
				else 
					printf("树为空!\n");
				break;
			case 13:
				MergeBBST(T1,T2);
				T2 = NULL;	break;
			case 0:
				system("cls");
				exit(0);
			default:
				printf("请规范输入!\n");
		}
		printf("按任意键返回>>>\n");
		getch();
	}
}

int main(){
	BBSTree T1 = NULL;
	BBSTree T2 = NULL;
	Start(T1,T2);
	return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!