文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何使用C语言实现平衡二叉树数据结构算法

2024-04-02 19:55

关注

前言

对于一个二叉排序树而言

那么我们通过二叉排序树的展示,会展示成如图:

在这里插入图片描述 

可以发现,如果我们想通过二叉排序树这个深度为8的树来查找某个数

我们需要走到最后,这是最坏的打算

但是如果我们能将该树改变为平衡二叉树,如图所示:

在这里插入图片描述 

相比之下我们这个深度为4的平衡二叉树在通过查询值时是效率很平均且稳定的,

那么通过上面的问题我们该怎么将这个二叉排序树的变成平衡二叉树是我们现在的问题了。

一、平衡二叉树实现原理

对于平衡二叉树的特性而言,我们在上面也有举例到

而我们该如何去计算该二叉排序树的平衡因子(平衡因子 = 左子树 - 右子树的值)呢?

我们可以结合上面那个最坏打算的二叉排序树的生成方式进行逐一分析。

如图:

在这里插入图片描述

可以看到当我们单步调试二叉排序树的时候到值1的时候值3的平衡因子为2>1

那么此时并不符合我们的平衡二叉树的规则

那么我们需要通过某种形式去调换,使其符合我们的平衡二叉树的规则

而图2就是由图1通过顺时针而得到出来的,在这里我们称为右旋

之后我们的值4继续插入,因为值4>值3,所以根据二叉排序树的特性是值3的右子树

那么也没出现什么问题之后继续插入下一个值5,因为值5>值4,所以值5会到值4的右子树上。

如图所示:

在这里插入图片描述

可以发现图4中当插入值5的时候,根节点、值3的平衡因子的绝对值=2

剩下就不多去演示了,整体是一个递归的过程

重要:在过程中反复的把不平衡的结点通过左、右旋的方式将其调整回平衡二叉树。

要想深刻了解平衡二叉树的实现原理请自行参考程杰著作的《大话数据结构》。

二、平衡二叉树实现算法

在类型上我们会通过二叉排序树的基础上添加一个bf,用于存储平衡因子,而定义了一个Status则是判断当前状态的代码。

代码如下:


typedef int Status;	

typedef  struct BiTNode	
{
	int data;	
	int bf; 
	struct BiTNode* lchild, * rchild;	
} BiTNode, * BiTree;

为了方便理解,我们前面的提到的左旋和右旋的方式,在c语言的代码中该如何实现呢?下面我们就来将代码展示出来。

代码如下:


void R_Rotate(BiTree* P)
{
	BiTree L;
	L = (*P)->lchild; 
	(*P)->lchild = L->rchild; 
	L->rchild = (*P);
	*P = L; 
}


void L_Rotate(BiTree* P)
{
	BiTree R;
	R = (*P)->rchild; 
	(*P)->rchild = R->lchild; 
	R->lchild = (*P);
	*P = R; 
}

我们可以看到左旋和右旋的代码很类似,所以我们通过了解了右旋的代码的含义自然就可以反推出左旋的含义了。

此函数的意思是:

如果文字还不了解我们可以将上述图1、图2的图片进行推导。

如图:

在这里插入图片描述 

那么左旋的操作就是一个逆时针的方向转换,代码也是类似这里就不再演示了。

现在我们来看左平衡旋转处理的代码函数:


#define LH +1  
#define EH 0   
#define RH -1  


void RightBalance(BiTree* T)
{
	BiTree R, Rl;
	R = (*T)->rchild; 
	switch (R->bf)
	{ 
	case RH: 
		(*T)->bf = R->bf = EH;
		L_Rotate(T);
		break;
	case LH: 
		Rl = R->lchild; 
		switch (Rl->bf)
		{ 
		case RH: (*T)->bf = LH;
			R->bf = EH;
			break;
		case EH: (*T)->bf = R->bf = EH;
			break;
		case LH: (*T)->bf = EH;
			R->bf = RH;
			break;
		}
		Rl->bf = EH;
		R_Rotate(&(*T)->rchild); 
		L_Rotate(T); 
	}
}


void LeftBalance(BiTree* T)
{
	BiTree L, Lr;
	L = (*T)->lchild; 
	switch (L->bf)
	{ 
	case LH: 
		(*T)->bf = L->bf = EH;
		R_Rotate(T);
		break;
	case RH: 
		Lr = L->rchild; 
		switch (Lr->bf)
		{ 
		case LH: (*T)->bf = RH;
			L->bf = EH;
			break;
		case EH: (*T)->bf = L->bf = EH;
			break;
		case RH: (*T)->bf = EH;
			L->bf = LH;
			break;
		}
		Lr->bf = EH;
		L_Rotate(&(*T)->lchild); 
		R_Rotate(T); 
	}
}


如图:

在这里插入图片描述

首先通过代码可以看到,我们定义了三个常数变量,分别代码1、0、-1。

然后呢因为是左平衡旋转处理我们需要获取当前图片所示的P结点(也就是我之前假设的根节点的顶点)的左子树,

这里要注意重点:

  1. 如果等于1了则执行一次右旋操作,即上图右旋推导的并且把它们的BF值(平衡因子)都改为0操作;
  2. 反之如果等于-1了则像上图一样进行双旋操作;
  3. 不过在那之前还要通过获取图2上L的右子树LR(贴合代码上的Lr);
  4. 然后再判断一下Lr的平衡因子的值并再次进行分支判断;
  5. 修改根节点P(即代码中的根节点T)根据Lr的BF值进行修改它们的BF值;
  6. 最后在将Lr的BF值赋为0,进行双旋操作这里先左旋后右旋;
  7. 那么右平衡旋转处理函数则取反。

三、全部代码


#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 
typedef int Status;	

typedef  struct BiTNode	
{
	int data;	
	int bf; 
	struct BiTNode* lchild, * rchild;	
} BiTNode, * BiTree;


void R_Rotate(BiTree* P)
{
	BiTree L;
	L = (*P)->lchild; 
	(*P)->lchild = L->rchild; 
	L->rchild = (*P);
	*P = L; 
}



void L_Rotate(BiTree* P)
{
	BiTree R;
	R = (*P)->rchild; 
	(*P)->rchild = R->lchild; 
	R->lchild = (*P);
	*P = R; 
}
#define LH +1  
#define EH 0   
#define RH -1  


void LeftBalance(BiTree* T)
{
	BiTree L, Lr;
	L = (*T)->lchild; 
	switch (L->bf)
	{ 
	case LH: 
		(*T)->bf = L->bf = EH;
		R_Rotate(T);
		break;
	case RH: 
		Lr = L->rchild; 
		switch (Lr->bf)
		{ 
		case LH: (*T)->bf = RH;
			L->bf = EH;
			break;
		case EH: (*T)->bf = L->bf = EH;
			break;
		case RH: (*T)->bf = EH;
			L->bf = LH;
			break;
		}
		Lr->bf = EH;
		L_Rotate(&(*T)->lchild); 
		R_Rotate(T); 
	}
}


void RightBalance(BiTree* T)
{
	BiTree R, Rl;
	R = (*T)->rchild; 
	switch (R->bf)
	{ 
	case RH: 
		(*T)->bf = R->bf = EH;
		L_Rotate(T);
		break;
	case LH: 
		Rl = R->lchild; 
		switch (Rl->bf)
		{ 
		case RH: (*T)->bf = LH;
			R->bf = EH;
			break;
		case EH: (*T)->bf = R->bf = EH;
			break;
		case LH: (*T)->bf = EH;
			R->bf = RH;
			break;
		}
		Rl->bf = EH;
		R_Rotate(&(*T)->rchild); 
		L_Rotate(T); 
	}
}



Status InsertAVL(BiTree* T, int e, Status* taller)
{
	if (!*T)
	{ 
		*T = (BiTree)malloc(sizeof(BiTNode));
		(*T)->data = e; (*T)->lchild = (*T)->rchild = NULL; (*T)->bf = EH;
		*taller = TRUE;
	}
	else
	{
		if (e == (*T)->data)
		{ 
			*taller = FALSE; return FALSE;
		}
		if (e < (*T)->data)
		{ 
			if (!InsertAVL(&(*T)->lchild, e, taller)) 
				return FALSE;
			if (*taller) 
				switch ((*T)->bf) 
				{
				case LH: 
					LeftBalance(T);	*taller = FALSE; break;
				case EH: 
					(*T)->bf = LH; *taller = TRUE; break;
				case RH: 
					(*T)->bf = EH; *taller = FALSE; break;
				}
		}
		else
		{ 
			if (!InsertAVL(&(*T)->rchild, e, taller)) 
				return FALSE;
			if (*taller) 
				switch ((*T)->bf) 
				{
				case LH: 
					(*T)->bf = EH; *taller = FALSE;	break;
				case EH: 
					(*T)->bf = RH; *taller = TRUE; break;
				case RH: 
					RightBalance(T); *taller = FALSE; break;
				}
		}
	}
	return TRUE;
}
int main(void)
{
	int i;
	int a[10] = { 3,2,1,4,5,6,7,10,9,8 };
	BiTree T = NULL;
	Status taller;
	for (i = 0; i < 10; i++)
	{
		InsertAVL(&T, a[i], &taller);
	}
	printf("本样例建议断点跟踪查看平衡二叉树结构");
	return 0;
}

到此这篇关于如何使用C语言实现平衡二叉树 的文章就介绍到这了,更多相关C语言实现平衡二叉树内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯