平衡二叉树的删除和插入的实现笔记

插入思路如图:
在这里插入图片描述插入就四种情况
1、右旋
2、先左旋再右旋
3、左旋
4、先右旋再左旋


删除的思路:
由于删除要考虑树的平衡状态,所以得用递归进行删除
比如删除30的数据,
1、查找30的节点,
2、找到之后,判断左树与右树的高度谁高,如果是左树高的话那就去左树寻找最右边的节点,反之就去找右树最左边的节点
3、找到该节点之后,比如他的数据是40,那就把40覆盖掉30,覆盖之后,继续删除,但是现在不是删除30了,删除的是40,继续递归往下找,找到40这个节点就可以收敛了,清除其内存就行

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <math.h>

typedef struct SHU{
	int num;
	int heght;
	struct SHU *left;
	struct SHU *right;
} ss;

int MABS(int a,int b);
int CheckHight(ss *head);
ss * Inselt(ss *head,int num) ;
void look(ss *head,int mode);
ss * Finemin(ss *head,ss*head2);
void myfree(ss *head);
ss *Xuanzhuan(ss *head,int mode);
ss * delete_avl(ss *head,int num);
int Findright(ss *temp);
int Findleft(ss *temp);


int MABS(int a,int b)
{
	if(a>b) return a-b;

	 return b-a;


}
int CheckHight(ss *head)
{
	if(head ==0) return -1;   //是空的话就层数表示-1
		
	return head->heght;


}

int GeiHight(ss *head1,ss *head2)
{
	int hight_lest=0,hight_right=0,temp=0;
	
	hight_lest=CheckHight(head1); // 获取当前左树高度
	hight_right=CheckHight(head2);// 获取当前右树高度
	if(hight_lest>hight_right){
		temp=hight_lest+1;
	}else{
		temp=hight_right+1;
	}	
	return temp;
}


//mode 0:左旋,1 先右后左,2 右旋3 先左后右

ss *Xuanzhuan(ss *head,int mode)
{
	ss *temp=0;
	ss *temp1=0;
	switch(mode){
		case 0:
				temp=head->left;//取出头部的左树
				
				head->left=temp->right;//将左树的右边赋值为头部的左边
					
				temp->right=head;  //左树的右边指向头部
				
				//更新的高度顺序不能乱,因为此时HEAD已经变成 temp的右节点了
				head->heght=GeiHight(head->left,head->right);

				temp->heght=GeiHight(temp->left,temp->right);
				
				return temp;  
				//刚开始我比较郁闷该怎么拼接,直接然会就行了,
				//我忽略了指针传参数的意义
			break;
		case 1:
				temp=head->left;//取出头部的左树
				temp1=temp->right;//
				//交换这两个数据测顺序
				head->left=temp1;
				temp->right=temp1->left; //保存temp1的左树到temp的右树
				temp1->left =temp;
				
				temp->heght=GeiHight(temp->left,temp->right);

				temp1->heght=GeiHight(temp1->left,temp1->right);

				//重复第一步的操作

				temp=head->left;//取出头部的左树
				
				head->left=temp->right;//将左树的右边赋值为头部的左边
					
				temp->right=head;  //左树的右边指向头部
				
				//更新的高度顺序不能乱,因为此时HEAD已经变成 temp的右节点了
				head->heght=GeiHight(head->left,head->right);

				temp->heght=GeiHight(temp->left,temp->right);
				
				return temp;  					
					

					
			break;
		case 2:
				temp=head->right;//取出头部的左树
				
				head->right=temp->left;//将左树的右边赋值为头部的左边
					
				temp->left=head;  //左树的右边指向头部
				
				//更新的高度顺序不能乱,因为此时HEAD已经变成 temp的右节点了
				head->heght=GeiHight(head->left,head->right);

				temp->heght=GeiHight(temp->left,temp->right);
				
				return temp; 

			break;
		case 3:
				temp=head->right;//取出头部的左树
				temp1=temp->left;//
				//交换这两个数据测顺序
				head->right=temp1;
				temp->left=temp1->right; //保存temp1的左树到temp的右树
				temp1->right =temp;
				temp->heght=GeiHight(temp->left,temp->right);
				temp1->heght=GeiHight(temp1->left,temp1->right);
                            //按第一步进行操作

				temp=head->right;//取出头部的左树
				
				head->right=temp->left;//将左树的右边赋值为头部的左边
					
				temp->left=head;  //左树的右边指向头部
				
				//更新的高度顺序不能乱,因为此时HEAD已经变成 temp的右节点了
				head->heght=GeiHight(head->left,head->right);

				temp->heght=GeiHight(temp->left,temp->right);
				
				return temp; 
                            
			break;
		default:

			return head;
			break;
	}


}


ss * Inselt(ss *head,int num)  //数的插入数据函数
{
	int hight_lest=0,hight_right=0;
	if(head==0){//空指针,先申请一波内存
		head=(ss *)malloc(sizeof(struct SHU));
		head->num=num;
		head->heght=0;
		head->left=0;
		head->right=0;
	}else{
		if(head->num<num){//如果当前的数据比当前的数据大那就往右边进行插入
			head->right=Inselt(head->right,num);
			hight_lest=CheckHight(head->left);
			hight_right=CheckHight(head->right);
			if(MABS(hight_lest,hight_right)>=2){
				//最好在这里进行判断,这样会很麻烦
				if(num>(head->right)->num){ //也就是说该新的数插到了最左边
					head=Xuanzhuan(head,2);
				}else{
					head=Xuanzhuan(head,3);
				}
			}
		}else{//如果当前的数据比当前的数据小那就往右边进行插入
			head->left=Inselt(head->left,num);
			hight_lest=CheckHight(head->left);
			hight_right=CheckHight(head->right);
			if(MABS(hight_lest,hight_right)>=2){
				//最好在这里进行判断,这样会很麻烦
				//这个=很需要,如果相等的数直接按小处理
				if(num<=(head->left)->num){ //也就是说该新的数插到了最左边
					head=Xuanzhuan(head,0);
				}else{
					head=Xuanzhuan(head,1);
				}
			}	
		}
		//从新进行对高度的
		head->heght=GeiHight(head->left,head->right);
		
	}
	return head;
}

//树的遍历 0 前序 1 中序 2后序

//前序 |根节点 |左边节点|右边节点

//中序 |左边节点 |根节点 |右边节点

//后序 |左边节点|右边节点 |根节点 

//所有的节点都已根节点为基准

void look(ss *head,int mode)
{
	switch(mode){
		case 0:
			if(head!=0){
				printf(" %d ",head->num);
				if(head->left!=0){
					look(head->left,mode);
				}
				if(head->right!=0){
					look(head->right,mode);
				}
			}
			break;
		case 1:
			if(head!=0){
				if(head->left!=0){
					look(head->left,mode);
				}
				printf(" %d ",head->num);

				if(head->right!=0){
					look(head->right,mode);
				}
			}
			break;
		default:
			if(head!=0){

				if(head->left!=0){
					look(head->left,mode);
				}
				if(head->right!=0){
					look(head->right,mode);
				}
				printf(" %d ",head->num);
			}			
			break;
	}

}

//删除的策略
//就是吧当前节点的指针替换成其右数最小的值即可
ss * Finemin(ss *head,ss*head2)
{
	ss *temp=head;
	if(temp==0){
		return 0;
	}else{
		while(temp->left!=0){
			temp=temp->left;
		}
	}
	return temp;
}



int Findright(ss *temp)
{
	ss *temp1=temp;	

	if(temp1!=0){  //当前有右节点的话,
		while(temp1->left!=0){ //找最左边的节点
			temp1=temp1->left; //继续往下搜索左树
		}
		
	}
	return temp1->num;
}

int Findleft(ss *temp)
{
	ss *temp1=temp;	


	if(temp1!=0){  //当前有右节点的话,
		while(temp1->right!=0){ //找最左边的节点
			temp1=temp1->right; //继续往下搜索左树
		}
		
	}
	return temp1->num;
}



//删除的策略第一步:就是先找出被删除的节点
//a判断左边的节点高还是右边的节点高
//b是左边的话找出其最大的叶子,
//c是右边的话找其最小的叶子
//d将上面找到的节点赋值给删除的节点,也就是覆盖掉他
//重新去删除BC两部找到的节点,一直找到最末尾的位置为止


ss * delete_avl(ss *head,int num) 
{
	int hight_lest=0,hight_right=0;
	int temonums=0;
	ss *temp=0;
	ss *temp1=0;
	ss *headtemp=head;
	if(head!=0){
		if(head->num==num){//找到删除的位置
			if((head->left==0)&&(head->right==0)){ //开始收敛了
				free(head);
				return 0;
			}else{
				hight_lest=CheckHight(head->left);
				hight_right=CheckHight(head->right);
				if(hight_lest>hight_right){//找左树最大的点
					temonums=Findleft(head->left);
				}else{
					temonums=Findright(head->right);
				}
				head->num=	temonums; //将值赋值给要删除的指针
				if(hight_lest>hight_right){
					head->left=delete_avl(head->left,temonums);
					hight_lest=CheckHight(head->left);
					hight_right=CheckHight(head->right);
					if(MABS(hight_lest,hight_right)>=2){
						if(hight_lest>hight_right){ 
							head=Xuanzhuan(head,0);
						}else{
							head=Xuanzhuan(head,2);
						}
					}
					head->heght=GeiHight(head->left,head->right);
					headtemp=head;
				}else{
					head->right=delete_avl(head->right,temonums);
					hight_lest=CheckHight(head->left);
					hight_right=CheckHight(head->right);
					if(MABS(hight_lest,hight_right)>=2){
						if(hight_lest>hight_right){ 
							head=Xuanzhuan(head,0);
						}else{
							head=Xuanzhuan(head,2);
						}
					}
					head->heght=GeiHight(head->left,head->right);
					headtemp=head;
				}
                   
			}
		}else if(head->num!=num) {

			if(head->num<num){
				head->right=delete_avl(head->right,num);
				hight_lest=CheckHight(head->left);
				hight_right=CheckHight(head->right);
				// 由于左边去掉的都是最大的,右边去掉的都是最小的
				//那么如果发生不平衡的事件就不会是双旋转
				if(MABS(hight_lest,hight_right)>=2){
					if(hight_lest>hight_right){ 
						head=Xuanzhuan(head,0);
					}else{
						head=Xuanzhuan(head,2);
					}
				}
				head->heght=GeiHight(head->left,head->right);
				headtemp=head;
			}else{
				head->left=delete_avl(head->left,num);
				hight_lest=CheckHight(head->left);
				hight_right=CheckHight(head->right);
				if(MABS(hight_lest,hight_right)>=2){
					if(hight_lest>hight_right){ 
						head=Xuanzhuan(head,0);
					}else{
						head=Xuanzhuan(head,2);
					}
				}
				head->heght=GeiHight(head->left,head->right);
				headtemp=head;
			}
		}
			
	}

	return headtemp;
}


void myfree(ss *head){
	if(head!=0){
		if(head->left!=0){
			myfree(head->left);
		}
		if(head->right!=0){
			myfree(head->right);
		}
		free(head);
	}
}


void main(void)
{
	ss *k=0,*temp=0;

	k=Inselt(k,60);
	k=Inselt(k,50);
	k=Inselt(k,40);
	k=Inselt(k,30);
	k=Inselt(k,20);
	k=Inselt(k,10);
	k=Inselt(k,10);
	k = Inselt(k, 70);
	
	
	k=delete_avl(k,50);
	k=delete_avl(k,60);
	k=delete_avl(k,40);
	
	temp=k;
	printf("\n----------------------\n");
	look(temp,0);
	printf("\n----------------------\n");
	myfree(k);
	

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值