平衡二叉树的创建

前言 :

  我们在学习树的时候,可发现树在一些极端环境下,结构变为一种单向的链式结构。

  这种结构,使得我们的查找的时间复杂度可能降到 n 。因此,人们就创造了平衡二叉树,平衡二叉树的设计,使得它的使用,在任何情况下,时间复杂度都为 log(n) 。

一、平衡二叉树的基本操作

平衡因子

   平衡二叉树相较普通的二叉树,在结点的设定上多了一个高度,这个高度的记录,就是为了计算结点的平衡因子。

  平衡因子即根结点的左右树的高度差值。平衡因子 = 左子树高度 - 右子树高度  ,当平衡因子为0、1、-1 的时候树为平衡状态,当平衡因子为2、-2 的时候,表示树失衡,需要通过左移或者右移来恢复平衡。

平衡二叉树的结点结构:

typedef struct AVL_Node
{
	int data;
	int height;
	struct AVL_Node* left;
	struct AVL_Node* right;
}AVL_Node, AVL_Tree;

平衡因子 =  root->left->height - root->right->height;

平衡二叉树的移动

平衡二叉树,借助平衡因子的值,进行判断是否需要左移或者右移。

右移:

 

 

void Rightmove(AVL_Tree& A)
{
	AVL_Tree New_node = A->left;
	AVL_Tree Old_node = A;
	Old_node->left = New_node->right;
	New_node->right = Old_node;
	Old_node->height = Height(Old_node);
    New_node->height = Height(New_node);
	A = New_node;
}

需要注意的是我们每次的旋转过后,我们必须要重新计算该结点的高度。

左移:

void Leftmove(AVL_Tree& A)
{
	AVL_Tree New_node = A->right;
	AVL_Tree Old_node = A;
	Old_node->right = New_node->left;
	New_node->left = Old_node;
	Old_node->height = Height(Old_node);
    New_node->height = Height(New_node);
	A = New_node;
}

 这里有一点需要特别注意,oldnode的高度计算一定要在newnode的前面。不然高度的计算会有错误!!!

 以上是两种基本的旋转方式,但是在实际使用中,我们还会遇到两种另外的情况。

其一:进行右旋的时候,左子树平衡因子为-1

 其二:进行左旋的时候,右子树的平衡因子为1

 

 

结点高度的计算

int Height(AVL_Tree A)
{
	if (A->left == NULL && A->right == NULL)
		return 1;
	else if (A->left != NULL && A->right == NULL)
		return A->left->height + 1;
	else if (A->right != NULL && A->left == NULL)
		return A->right->height + 1;
	else
		return A->left->height > A->right->height ? A->left->height + 1 : A->right->height + 1;
}

这里每个结点的初始高度为1,所以每层加1。

平衡因子的计算

int BF(AVL_Tree A)
{
	if (A->left == NULL && A->right == NULL)
		return 0;
	else if (A->left != NULL && A->right == NULL)
		return A->left->height;
	else if (A->right != NULL && A->left == NULL)
		return -A->right->height;
	else
		return A->left->height - A->right->height;
}

以上是平衡二叉树的基本操作

二、平衡二叉树的创建

结点插入

void Insert(AVL_Tree& A, int B)
{
	if (A == NULL)
	{
		Create_node(A, B);
		return;
	}
	if (A->data > B)
		Insert(A->left, B);
	else
		Insert(A->right, B);
	A->height = Height(A);
	if (BF(A) == 2)
	{
		if (A->left != NULL && BF(A->left) == -1)//这里记得判断A->left是否为空指针
			Leftmove(A->left);
		Rightmove(A);
	}
	else if (BF(A) == -2)
	{
		if (A->right != NULL && BF(A->right) == 1)//这里记得判断A->right是否为空指针
			Rightmove(A->right);
		Leftmove(A);
	}
}

插入的实现是递归的操作,因为结点的高度是随着每个结点的插入改变的。

树的创建

void Create_Tree(AVL_Tree& A, int* arr, int num)
{
	int rab = 0;
	for (rab = 0; rab < num; rab++)
	{
		Insert(A, arr[rab]);
	}
}

树的遍历

void In_order(AVL_Tree A)
{
	if (A->left != NULL)
		In_order(A->left);
	printf("%d %d\n", A->data, A->height);
	if (A->right != NULL)
		In_order(A->right);
}

平衡二叉树的创建就到这了,我们可以发现平衡二叉树的平衡是绝对的平衡,使得我们在查找的时候,效率特别高。但是缺点也很明显,就是频繁的旋转,导致时间的流失。

谢谢观看!!!

有错误,多多指教!!!

全部代码:

typedef struct AVL_Node
{
	int data;
	int height;
	struct AVL_Node* left;
	struct AVL_Node* right;
}AVL_Node, *AVL_Tree;

int Height(AVL_Tree A)
{
	if (A->left == NULL && A->right == NULL)
		return 1;
	else if (A->left != NULL && A->right == NULL)
		return A->left->height + 1;
	else if (A->right != NULL && A->left == NULL)
		return A->right->height + 1;
	else
		return A->left->height > A->right->height ? A->left->height + 1 : A->right->height + 1;
}

int BF(AVL_Tree A)
{
	if (A->left == NULL && A->right == NULL)
		return 0;
	else if (A->left != NULL && A->right == NULL)
		return A->left->height;
	else if (A->right != NULL && A->left == NULL)
		return -A->right->height;
	else
		return A->left->height - A->right->height;
}

void Rightmove(AVL_Tree& A)
{
	AVL_Tree New_node = A->left;
	AVL_Tree Old_node = A;
	Old_node->left = New_node->right;
	New_node->right = Old_node;
	Old_node->height = Height(Old_node);
	New_node->height = Height(New_node);
	A = New_node;
}

void Leftmove(AVL_Tree& A)
{
	AVL_Tree New_node = A->right;
	AVL_Tree Old_node = A;
	Old_node->right = New_node->left;
	New_node->left = Old_node;
	Old_node->height = Height(Old_node);
	New_node->height = Height(New_node);
	A = New_node;
}

void Create_node(AVL_Tree& A, int B)
{
	A = (AVL_Tree)malloc(sizeof(AVL_Node));
	A->data = B;
	A->height = 1;
	A->left = A->right = NULL;
}

void Insert(AVL_Tree& A, int B)
{
	if (A == NULL)
	{
		Create_node(A, B);
		return;
	}
	if (A->data > B)
		Insert(A->left, B);
	else
		Insert(A->right, B);
	A->height = Height(A);
	if (BF(A) == 2)
	{
		if (A->left != NULL && BF(A->left) == -1)
			Leftmove(A->left);
		Rightmove(A);
	}
	else if (BF(A) == -2)
	{
		if (A->right != NULL && BF(A->right) == 1)
			Rightmove(A->right);
		Leftmove(A);
	}

}

void Create_Tree(AVL_Tree& A, int* arr, int num)
{
	int rab = 0;
	for (rab = 0; rab < num; rab++)
	{
		Insert(A, arr[rab]);
	}
}

void In_order(AVL_Tree A)
{
	if (A->left != NULL)
		In_order(A->left);
	printf("%d %d\n", A->data, A->height);
	if (A->right != NULL)
		In_order(A->right);
}

int main()
{
	AVL_Tree root = NULL;
	int arr[] = {1,12,44,32,65,89,15,21,34,35,68,49};
	int num = sizeof(arr) / sizeof(arr[0]);
	Create_Tree(root, arr, num);
	In_order(root);
	return 0;
}

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值