插入思路如图:
插入就四种情况
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);
}