问题描述
给定一个二叉树(存储结构采用二叉链表表示),试设计算法判断该二叉树 是否为 AVL 树。
AVL树的概念
AVL树是一种平衡二叉搜索树,AVL树有一个特点,所有节点的平衡因子的绝对值不能大于1,即所有节点的左子树与右子树的深度差只能为-1,0,1。
需求分析
判断AVL树的思路很简单,只要判断是否是二叉搜索树,再判断是否带有平衡条件
代码实现
(1)结构体、全局变量的定义
typedef struct btree{
int data ;
struct btree* lchild;
struct btree* rchild;
}BTree,*Root;
int a[10];//全局变量,用于中序遍历存放节点
int n=0;//全局变量,用于记录每棵二叉树的节点数,并在下次建树前重新归0
(2)AVL树的判断
//判断二叉树是否是AVL树,两个条件:1是搜索树 2.是平衡树
bool isAVL(Root T){
if(isBST(T) && isBalance(T))
return true;
return false;
}
(3)判断二叉树是否是搜索树
二叉搜索树的概念是所有节点的左孩子都比它小,右孩子都比它大。所以显而易见如果将一棵二叉树以中序遍历输出,那么得到的节点序列就是按照升序排列,依照这个规律就可以判断二叉树是否是搜索树。
bool isBST(Root root){
InOrder(root);//中序遍历到数组a中
return isOrdered(a,n);//调用isOrdered函数判断二叉树的中序遍历是否是升序的,如果是,那么此二叉树就是二叉搜索树
}
(4)判断二叉树是否满足平衡条件
先判断二叉树是否是空,如果是则直接返回true。内部通过递归计算出左子树和右子树的高度,并计算两者差的绝对值。最后通过递归返回所有节点的平衡因子小于等于1的bool值,当且仅当所有节点的平衡因子都满足条件则函数返回true。
//判断二叉树是否是二叉平衡树
bool isBalance(Root root){
if(!root)
return true;
int ldepth=getDepth(root->lchild);
int rdepth=getDepth(root->rchild);
int abs_depth=abs(ldepth-rdepth);
return abs_depth<=1 && isBalance(root->lchild) && isBalance(root->rchild);
}
源代码
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
typedef struct btree{
int data ;
struct btree* lchild;
struct btree* rchild;
}BTree,*Root;
int a[10];//全局变量,用于中序遍历存放节点
int n=0;//全局变量,用于记录每棵二叉树的节点数,并在下次建树前重新归0
Root CreateTree();
void InOrder(Root T);
bool isOrdered(int a[],int length);
bool isBST(Root root);
int getDepth(Root root);
bool isBalance(Root root);
bool isAVL(Root T);
void output();
int main(){
char c;
Root T;
printf("********************AVL树判定程序**************************\n");
printf("******** 注意事项: *********\n");
printf("******** 1.以先序遍历输入二叉树 *********\n");
printf("******** 2.空节点用0代替 *********\n");
printf("******** 3.叶子节点的左右孩子用0代替 *********\n");
printf("******** 4.每输入一个节点后按回车 *********\n");
printf("***********************************************************\n");
do{
printf("***********************************************************\n");
printf(" Input:\n");
T = CreateTree();
getchar();
printf(" Ouput:\n");
bool YN=isAVL(T);
printf(" 此二叉树的中序遍历结果为:");
output();
if(YN)
printf(" 此二叉树是AVL树\n");
else{
printf(" 此二叉树不是AVL树\n");
if(isBST(T))
printf(" 原因:存在平衡因子超过1的节点\n");
else
printf(" 原因:此二叉树不是二叉搜索树\n");
}
n=0;//归零,用于下次判定
printf(" 任意键继续,按0结束程序:");
c=getchar();
if(c=='0')
printf(" 程序结束!\n");
}while(c!='0');
return 0;
}
//先序遍历建树
Root CreateTree() {
Root T;
int x;
printf(" 请输入节点:");
scanf("%d",&x);
if(x == 0){
T = NULL;
}
else{
T = (Root)malloc(sizeof(BTree));
T->data = x;
T->lchild = CreateTree();
T->rchild = CreateTree();
}
return T;
}
//判断二叉树是否是AVL树,两个条件:1是搜索树 2.是平衡树
bool isAVL(Root T){
if(isBST(T) && isBalance(T))
return true;
return false;
}
//判断二叉树是否是二叉搜索树
bool isBST(Root root){
InOrder(root);//中序遍历到数组a中
return isOrdered(a,n);//调用isOrdered函数判断二叉树的中序遍历是否是升序的,如果是,那么此二叉树就是二叉搜索树
}
//判断二叉树是否是二叉平衡树
bool isBalance(Root root){
if(!root)
return true;
int ldepth=getDepth(root->lchild);
int rdepth=getDepth(root->rchild);
int abs_depth=abs(ldepth-rdepth);
return abs_depth<=1 && isBalance(root->lchild) && isBalance(root->rchild);
}
//以中序遍历的顺序将节点的值的放入数组中
void InOrder(Root T){
if(T){
InOrder(T->lchild);
a[n++]=T->data;//将节点值放入数组中
InOrder(T->rchild);
}
}
//判断数组是否是升序
bool isOrdered(int a[],int length){
for(int i=0;i<length-1;i++)
if(a[i]>=a[i+1])
return false;
return true;
}
//计算树的深度,isBalance需要的函数
int getDepth(Root root){
int ldepth,rdepth;
if(!root)
return 0;
else{
ldepth=getDepth(root->lchild);
rdepth=getDepth(root->rchild);
return ldepth>rdepth ? ldepth+1 : rdepth+1;
}
}
//遍历数组
void output(){
for(int j=0;j<n;j++)
printf("%d ",a[j]);
printf("\n");
}