main.c
#include<stdio.h>
#include<stdlib.h>
#include"AVLTree.h"
int main()
{
Tree * t = createTree();
TNode * p = NULL;
tElemType x;
while(1)
{
scanf("%d",&x);
if(x==0)
break;
p = (TNode *)malloc(sizeof(TNode));
p->data = x;
p->height = 1;
p->lchild = p->rchild = NULL;
t->root = insert(t->root,p);
}
Midorder(t->root);
return 0;
}
list.h
#ifndef __AVLTREE_H__
#define __AVLTREE_H__
typedef int tElemType;
struct tNode//节点类型
{
tElemType data;//数据域,保存节点数据
struct tNode * lchild;//指针域,保存左孩子的地址
struct tNode * rchild;//指针域,保存右孩子的地址
int height;//保存以该节点为根节点的二叉树的高度。平衡二叉树中经常需要判断是否平衡,所以我们保存高度这个重要信息
};
typedef struct tNode TNode;
struct tree//树的头结点,保存树的有用信息
{
TNode * root;//保存根节点的地址
int n;//节点个数
};//头结点
typedef struct tree Tree;
//中序遍历以 root为根节点的二叉树
void Midorder(TNode * root);
/*
功能:用递归的方法把p节点插入到以root为根节点的二叉树中
参数:
@root 这棵二叉树的根节点地址
@p 待插入的节点地址
返回值:
返回插入节点之后的二叉树的根节点
思考:
1,第一个参数为什么不传入头结点,而是传入根节点
2,第二个参数为什么不传入 TElemType类型,而是传入 TNode *类型
因为如果传入 TElemType类型,就得在函数内部 malloc分配空间,
而该函数又是递归调用的,就会重复malloc分配空间
*/
TNode* insert(TNode * root,TNode * p);
/*
功能:创建一棵空树
返回值:
返回头结点地址
*/
Tree * createTree();
/*
功能:单向右旋平衡处理
参数:
@root 待平衡处理的二叉树的根节点
返回值:
平衡处理之后的二叉树的根节点
*/
TNode * right(TNode * root);
/*
功能:单向右旋平衡处理
参数:
@root 待平衡处理的二叉树的根节点
返回值:
平衡处理之后的二叉树的根节点
*/
TNode * left(TNode * root);
/*
先右后左旋转平衡处理
参数:
@root 待平衡处理的二叉树的根节点
返回值:
平衡处理之后的二叉树的根节点
*/
TNode * rightLeft(TNode * root);
TNode * leftRight(TNode * root);
#endif
list.c
#include<stdio.h>
#include<stdlib.h>
#include"AVLTree.h"
#define MAX(x,y) ((x)>(y)?(x):(y))
int nodeHeight(TNode * p)
{
if(p == NULL)
{
return 0;
}
else
{
return p->height;
}
}
/*
功能:创建一棵空树
返回值:
返回头结点地址
*/
Tree * createTree()
{
Tree * t = (Tree *)malloc(sizeof(Tree));
t->root = NULL;
t->n = 0;
return t;
}
/*
功能:用递归的方法把p节点插入到以root为根节点的二叉树中
参数:
@root 这棵二叉树的根节点地址
@p 待插入的节点地址
返回值:
返回插入节点之后的二叉树的根节点
思考:
1,第一个参数为什么不传入头结点,而是传入根节点
2,第二个参数为什么不传入 TElemType类型,而是传入 TNode *类型
因为如果传入 TElemType类型,就得在函数内部 malloc分配空间,
而该函数又是递归调用的,就会重复malloc分配空间
*/
TNode* insert(TNode * root,TNode * p)
{
if(root == NULL)
{
return p;
}
int l,r;
if(p->data < root->data)//要插入的节点比根节点小,应该要插入到它的左子树中
{
root->lchild = insert(root->lchild,p);
l = nodeHeight(root->lchild);
r = nodeHeight(root->rchild);
root->height = MAX(l,r)+1;
//当不平衡的时候才需要进行旋转操作
if(abs(l-r) > 1)
{
//此时是往左子树进行插入,可以分为两种情况 左左插入 和 左右插入
if(root->lchild!=NULL && p->data < root->lchild->data)//左左插入
{
//进行右旋
root = right(root);
}
else if(root->lchild!=NULL && p->data > root->lchild->data)//左右插入
{
//进行 先左后右旋转
root = leftRight(root);
}
}
}
else if(p->data > root->data)
{
root->rchild = insert(root->rchild, p);
l = nodeHeight(root->lchild);
r = nodeHeight(root->rchild);
root->height = MAX(l,r)+1;
//当不平衡的时候才需要进行旋转操作
if(abs(l-r) > 1)
{
//此时是往右子树进行插入,可以分为两种情况 右左插入 和 右右插入
if(root->rchild!=NULL && p->data < root->rchild->data)//右左插入
{
//进行 先右后左旋
root = rightLeft(root);
}
else if(root->rchild!=NULL && p->data > root->rchild->data)//右右插入
{
//进行 先左后右旋转
root = left(root);
}
}
}
else
{
free(p);
}
return root;
}
//中序遍历以 root为根节点的二叉树
void Midorder(TNode * root)
{
//如果是空树,就不需要访问,直接结束
if(root == NULL)
{
return ;
}
//以中序遍历的方法访问左子树
Midorder(root->lchild);
printf("%d(%d) ",root->data,root->height);
//以中序遍历的方法访问左子树
Midorder(root->rchild);
}
/*
功能:单向右旋平衡处理
参数:
@root 待平衡处理的二叉树的根节点
返回值:
平衡处理之后的二叉树的根节点
*/
TNode * right(TNode * root)
{
if(root == NULL)
return NULL;
TNode * k2 = root;
TNode * k1 = k2->lchild;
k2->lchild = k1->rchild;
k1->rchild = k2;
//旋转完成之后需要更新节点的高度
//先更新k2,再更新k1,顺序不能倒过来。 k1的高度依赖k2的高度
int l,r;
l = nodeHeight(k2->lchild);
r = nodeHeight(k2->rchild);
k2->height = MAX(l,r) + 1;
l = nodeHeight(k1->lchild);
r = nodeHeight(k1->rchild);
k1->height = MAX(l,r) + 1;
return k1;
}
/*
功能:单向右旋平衡处理
参数:
@root 待平衡处理的二叉树的根节点
返回值:
平衡处理之后的二叉树的根节点
*/
TNode * left(TNode * root)
{
if(root == NULL)
return NULL;
TNode * k2 = root;
TNode * k1 = k2->rchild;
k2->rchild = k1->lchild;
k1->lchild = k2;
int l,r;
l = nodeHeight(k2->lchild);
r = nodeHeight(k2->rchild);
k2->height = MAX(l,r) + 1;
l = nodeHeight(k1->lchild);
r = nodeHeight(k1->rchild);
k1->height = MAX(l,r) + 1;
return k1;
}
/*
先右后左旋转平衡处理
参数:
@root 待平衡处理的二叉树的根节点
返回值:
平衡处理之后的二叉树的根节点
*/
TNode * rightLeft(TNode * root)
{
if(root == NULL)
return NULL;
root->rchild = right(root->rchild);
TNode * k = left(root);
return k;
}
TNode * leftRight(TNode * root)
{
if(root == NULL)
return NULL;
root->lchild = left(root->lchild);
TNode * k = right(root);
return k;
}