AVL树C语言实现

#ifndef AVLTREE_H_
#define AVLTREE_H_

#define FLOWOVER -1

struct AVLTreeADT;
typedef struct AVLTreeADT * AVLTree;//根指针,与节点指针本质一样
typedef struct AVLTreeADT * AVLNode;//节点指针
typedef int ElemType;//数据域数据类型

struct AVLTreeADT{
	ElemType elem;//数据域
	AVLTree left;//树节点左儿子指针
	AVLTree right;//树节点右儿子指针
	int height;//当前节点的高度,空节点为-1,只有本身的节点的高度为0
};

//辅助函数,返回输入节点的高度
static int Height(AVLNode N);
//辅助函数,返回输入两高度值中大的那一个
static int Max(int height_1, int height_2);
//辅助函数,有左儿子的单旋转,对N的左儿子的左子树进行一次插入后调用
static AVLNode SingleRotateWithLeft(AVLNode N);
//辅助函数,有右儿子的单旋转,对N的右儿子的右子树进行一次插入后调用
static AVLNode SingleRotateWithRight(AVLNode N);
//辅助函数,有左儿子的双旋转,对N的左儿子的右子树进行一次插入后调用
static AVLNode DoubleRotateWithLeft(AVLNode N);
//辅助函数,有右儿子的双旋转,对N的右儿子的左子树进行一次插入后调用
static AVLNode DoubleRotateWithRight(AVLNode N);
//清空树,返回根指针
AVLTree MakeEmpty(AVLTree T);
//在树中查找是否存在E,找到则返回true
bool Find(ElemType E, AVLTree T);
//查找树中的最小值,返回,若为空树,返回-1
ElemType FindMin(AVLTree T);
//查找树中的最大值,返回,若为空树,返回-1
ElemType FindMax(AVLTree T);
//向树T中插入E,返回根地址
AVLTree Insert(ElemType E, AVLTree T);
//从树T中删除E,返回根地址
AVLTree Delete(ElemType E, AVLTree T);
//检索,输入节点指针,返回该节点对应的节点的数据域
ElemType Retrieve(AVLNode N);
//中序遍历树B并打印,值域为空则输出0
void PrintTree(AVLTree T);

#endif


#include <stdio.h>
#include <stdlib.h>
#include "AVLTree.h"

static int Height(AVLNode N)
{//static表示函数可见性仅为定义文件
	if (N == NULL){
		return -1;
	}
	else{
		return N->height;
	}
}

static int Max(int height_1, int height_2)
{
	if (height_1 > height_2){
		return height_1;
	}
	else{
		return height_2;
	}
}

static AVLNode SingleRotateWithLeft(AVLNode N)
{//图见课本P82、P88,结合图画一遍基本就能理解原理了
	AVLNode leftSonOfN;
	leftSonOfN = N->left;
	N->left = leftSonOfN->right;
	leftSonOfN->right = N;

	N->height = Max(Height(N->left), Height(N->right));//重置节点深度
	leftSonOfN->height = Max(Height(leftSonOfN->left), Height(leftSonOfN->right));

	return leftSonOfN;
}

static AVLNode SingleRotateWithRight(AVLNode N)
{//图见课本P82、P88
	AVLNode rightSonOfN;
	rightSonOfN = N->right;
	N->right = rightSonOfN->left;
	rightSonOfN->left = N;

	N->height = Max(Height(N->left), Height(N->right));//重置节点深度
	rightSonOfN->height = Max(Height(rightSonOfN->left), Height(rightSonOfN->right));

	return rightSonOfN;//返回新的树根
}

static AVLNode DoubleRotateWithLeft(AVLNode N)
{//图见课本P84、P89
	N->left = SingleRotateWithRight(N->left); //以N->left为节点完成第一次单右旋转
	return SingleRotateWithLeft(N); //以N为节点完成第二次单左旋转,并返回根节点
}

static AVLNode DoubleRotateWithRight(AVLNode N)
{//图见课本P84、P89
	N->right = SingleRotateWithLeft(N->right);
	return SingleRotateWithRight(N);
}

AVLTree MakeEmpty(AVLTree T)
{//唯一根节点T = NULL表示树为空
	if (T != NULL){
		MakeEmpty(T->left);
		MakeEmpty(T->right);
		free(T);
	}
	return NULL;
}

ElemType FindMin(AVLTree T)
{
	if (T != NULL){
		if (T->left == NULL){
			return T->elem;
		}
		else{
			return FindMin(T->left);//递归查找左子树的左子树,最小值一定在最左边  
		}
	}
	return -1;//树为空,返回-1  
}

ElemType FindMax(AVLTree T)
{
	if (T != NULL){
		if (T->left == NULL){
			return T->elem;
		}
		else{
			return FindMax(T->right);//递归查找右子树的右子树,最大值一定在最右边  
		}
	}
	return -1;//树为空,返回-1  
}

AVLTree Insert(ElemType E, AVLTree T)
{
	if (T == NULL){
		T = (AVLTree)malloc(sizeof(struct AVLTreeADT));
		if (T == NULL)
			exit(FLOWOVER);
		else{
			T->elem = E;
			T->left = NULL;
			T->right = NULL;
		}
	}

	else if (E < T->elem){
		T->left = Insert(E, T->left);//往左边插入,深度增加的必为左边
		if (Height(T->left) - Height(T->right) == 2){
			if (E < T->left->elem){
				T = SingleRotateWithLeft(T);
			}
			else{
				T = DoubleRotateWithLeft(T);
			}
		}
	}

	else if (E > T->elem){
		T->right = Insert(E, T->right);
		if (Height(T->right) - Height(T->left) == 2){
			if (E > T->right->elem){
				T = SingleRotateWithRight(T);
			}
			else{
				T = DoubleRotateWithRight(T);
			}
		}
	}

	else{//重复插入,不做任何操作,直接返回
		return T;
	}

	T->height = Max(Height(T->left), Height(T->right));//每次递归回退后更新节点高度
	return T;
}

AVLTree Delete(ElemType E, AVLTree T)
{//删除的点可能不属于需要旋转的树,如何处理
	if (T != NULL){//判断是否为空树
		if (T->elem == E){//如果找到了
			if (T->left == NULL || T->right == NULL){//没有子节点或只有一个子节点
				AVLNode tempPtr = T;
				if (T->right == NULL){//没有子节点或只有左节点
					T = T->left;
					free(tempPtr);
				}
				else if (T->left == NULL){//只有右节点
					T = T->right;
					free(tempPtr);
				}
			}

			else{//有两个儿子,用其右子树中最小的数据代替该节点的数据,然后递归删除
				T->elem = FindMin(T->right);
				T->right = Delete(T->elem, T->right);//相当于用右子树中最小的节点覆盖删除节点,然后删除右子树中的那个节点
			}
		}

		else if (E < T->elem){//如果没找到,继续搜索左子树
			T->left = Delete(E, T->left);
			T->height = Max(Height(T->left), Height(T->right));//每次递归回退后更新节点高度
			if (Height(T->right) - Height(T->left) == 2){//若两子树高度差为2,则通过旋转修复
				if (Height(T->right->left) > Height(T->right->right)){//通过子树的左右子树深度判断需要采用哪种修复方式
					T = DoubleRotateWithRight(T);
				}
				else if (Height(T->right->left) < Height(T->right->right)){
					T = SingleRotateWithRight(T);
				}
				else{//当子树的左右子树深度相同时,有可能会导致一次修复还不够,需要补充修复一次,具体自己画图可知
					T = DoubleRotateWithRight(T);
					if (Height(T->right->right) - Height(T->right->left) == 2){
						T->right = SingleRotateWithRight(T->right);
					}
				}
			}
		}

		else{//如果没找到,继续搜索右子树
			T->right = Delete(E, T->right);
			T->height = Max(Height(T->left), Height(T->right));//每次递归回退后更新节点高度
			if (Height(T->left) - Height(T->right) == 2){
				if (Height(T->left->left) > Height(T->left->right)){
					T = SingleRotateWithLeft(T);
				}
				else if (Height(T->left->left) < Height(T->left->right)){
					T = DoubleRotateWithLeft(T);
				}
				else{
					T = DoubleRotateWithLeft(T);
					if (Height(T->left->left) - Height(T->left->right) == 2){
						T->left = SingleRotateWithLeft(T->left);
					}
				}
			}
		}
	}

	else{//空树,不做任何操作,直接回退
		return T;
	}


	return T;
}

ElemType Retrieve(AVLNode N)
{
	if (N != NULL){
		return N->elem;
	}
	else
		return -1;
}

void PrintTree(AVLTree T)
{
	if (T == NULL){
		printf("0 ");
	}
	else{
		PrintTree(T->left);
		printf("%d ", T->elem);
		PrintTree(T->right);
	}
}


#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "AVLTree.h"

int main(){
	srand((int)time(0));
	AVLTree testTree = NULL;

	while (1){

		int a[20];//生成20个随机数存入树中
		for (int i = 0; i < 20; i++){
			int flag = 1;
			a[i] = rand() % 100 + 1;
			while (flag != 0 && i != 0){
				for (int k = 0; k < i; k++){
					if (a[k] == a[i]){
						a[i] = rand() % 100 + 1;
						break;
					}
					if (k == i - 1){
						flag = 0;
					}
				}
			}
			testTree = Insert(a[i], testTree);
		}

		printf("testTree初始化为:");
		PrintTree(testTree);
		printf("\n");

		int b[10];//生成十个不同的随机数,作为a[20]的下标
		for (int i = 0; i < 10; i++){
			b[i] = rand() % 20;
			int flag = 1;
			while (flag != 0 && i != 0){
				for (int k = 0; k < i; k++){
					if (b[k] == b[i]){
						b[i] = rand() % 20;
						break;
					}
					if (k == i - 1){
						flag = 0;
					}
				}
			}
		}

		for (int i = 0; i < 10; i++){//随机删除十个数,每删除一个打印一次
			testTree = Delete(a[b[i]], testTree);
			printf("删除%d后,testTree为:", a[b[i]]);
			PrintTree(testTree);
			printf("\n");
		}

		testTree = MakeEmpty(testTree);

		system("pause");
	}
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值