学了两个星期才把代码实现出来,速度很慢但是我在坚持。
首先要知道,二叉搜索树的特性:
左儿子比父亲节点小;右儿子比父亲节点大。拥有这一特性,我们对二叉树进行查找就会方便很多。
但是在建立二叉搜索树的时候,如果输入序列是从大到小排列的,不加以调整的话,就会出现把数字一个一个往左儿子放的情况;
即退化成线性表。这样显然会耗费更多的时间。(输入序列从小到大同理)所以我们要对二叉搜索树的插入加以调整;
这一过程就叫做平衡化处理;得出来的二叉搜索树也称作平衡二叉搜索树。(AVL树)
AVL树有这样的特性:
1、任一节点的左右子树均为AVL树;
2、根节点左右子树的高度差的绝对值不超过1;(超过1就要进行平衡化处理)
AVL树的结构:
//平衡二叉搜索树
typedef struct node{
struct node *left;
struct node *right;
int date;
int height; //高度是它的标配
}AVLTree;
先写一个求较大者的Max函数,方便后面的运算:
int Max(int a,int b)
{
if(a>b)
return a;
if(b>a)
return b;
}
我们要有一个求树高的函数:
int GetHeight(AVLTree *T) //求树高函数
{
int h1,h2,maxh;
if(T!=NULL)
{
h1=GetHeight(T->left); //递归求左子树高
h2=GetHeight(T->right); //递归求右子树高
maxh=(Max(h1,h2)); //取较大者
return (maxh+1);
}
else
return 0; //空树树高为0
}
平衡化处理:
首先要知道不平衡的情况有四种:
我们需要写出解决这四种不平衡的解决方式
左单旋:
AVLTree *turnleft(AVLTree *T) //左单旋
{
AVLTree *B;
B=T->left;
T->left=B->right;
B->right=T;
T->height=Max(GetHeight(T->left),GetHeight(T->right))+1; //更新高度
B->height=Max(GetHeight(B->left),GetHeight(B->right))+1;
return B;
}
右单旋:
AVLTree *turnright(AVLTree *T)//右单旋
{
AVLTree *B;
B=T->right;
T->right=B->left;
B->left=T;
T->height=Max(GetHeight(T->left),GetHeight(T->right))+1; //更新高度
B->height=Max(GetHeight(B->left),GetHeight(B->right))+1;
return B;
}
左-右旋:
AVLTree *turnleftright(AVLTree *T) //左-右旋
{
T->left=turnright(T->left); //先来一次右单旋
return turnleft(T); //再来一次左单旋
}
右-左旋:
AVLTree *turnrightleft(AVLTree *T)//右-左旋
{
T->right=turnleft(T->right);
return turnright(T);
}
完整代码:
#include<stdio.h>
#include<stdlib.h>
//平衡二叉搜索树
typedef struct node{
struct node *left;
struct node *right;
int date;
int height;
}AVLTree;
int Max(int a,int b)
{
if(a>b)
return a;
if(b>a)
return b;
}
int GetHeight(AVLTree *T) //求树高函数
{
int h1,h2,maxh;
if(T!=NULL)
{
h1=GetHeight(T->left);
h2=GetHeight(T->right);
maxh=(Max(h1,h2));
return (maxh+1);
}
else
return 0;
}
AVLTree *turnleft(AVLTree *T) //左单旋
{
AVLTree *B;
B=T->left;
T->left=B->right;
B->right=T;
T->height=Max(GetHeight(T->left),GetHeight(T->right))+1; //更新高度
B->height=Max(GetHeight(B->left),GetHeight(B->right))+1;
return B;
}
AVLTree *turnright(AVLTree *T)//右单旋
{
AVLTree *B;
B=T->right;
T->right=B->left;
B->left=T;
T->height=Max(GetHeight(T->left),GetHeight(T->right))+1; //更新高度
B->height=Max(GetHeight(B->left),GetHeight(B->right))+1;
return B;
}
AVLTree *turnleftright(AVLTree *T) //左-右旋
{
T->left=turnright(T->left); //先来一次右单旋
return turnleft(T); //再来一次左单旋
}
AVLTree *turnrightleft(AVLTree *T)//右-左旋
{
T->right=turnleft(T->right);
return turnright(T);
}
AVLTree *insert(AVLTree *T,int x) //平衡搜索二叉树插入
{
if(T==NULL)
{
T=(AVLTree*)malloc(sizeof(AVLTree));
T->date=x;
T->left=NULL;
T->right=NULL;
T->height=1;
return T;
}
if(x<T->date) //比左儿子小的话 要么左单旋要么左右旋
{
T->left=insert(T->left,x); //往左边放
if(GetHeight(T->left)-GetHeight(T->right)==2)
{
if(x<T->left->date)
T=turnleft(T); //左单旋
else
T=turnleftright(T); //否则左右旋
}
}
if(x>T->date)
{
T->right=insert(T->right,x);
if(GetHeight(T->right)-GetHeight(T->left)==2)
{
if(x>T->right->date)
T=turnright(T);
else
T=turnrightleft(T);
}
}
T->height=Max(GetHeight(T->left),GetHeight(T->right))+1; //更新树高
return T;
}
void printftree(AVLTree *T) //遍历树 先序遍历
{
if(T!=NULL)
{
printf("%d ",T->date);
printftree(T->left);
printftree(T->right);
}
return;
}
int main()
{
int x;
AVLTree *BT;
BT=NULL;
scanf("%d",&x);
while(x!=-1)
{
BT=insert(BT,x);
scanf("%d",&x);
}
printftree(BT);
return 0;
}