基于C语言的平衡二叉树操作(包含完整代码)

news2024/11/19 7:35:14

平衡二叉树的定义:

 为避免树的高度增长过快,降低二叉排序树的性能,规定在插入和删除二叉树结点时,要保证任意结点的左、右子树高度差的绝对值不超过1,将这样的二义树称为平衡二叉树AVL (Balanced Binary Tree),简称平衡树。

平衡二叉树的插入:

(1) LL平衡旋转(右单旋)

由于在结点A的左孩子(L的在子树(L上插入了新结点,A的平衡因子由1增至2,导致以A为根的子树大去平衡,需要一次向右的旋转操作。将A的左孩子B向右上旋转代替A成为根结点,将A结点向右下旋转成为B的右子树的根结点,而B的原右子树则作为A结点的左子树。
如图7.11所示,结点旁的数值代表结点的平衡因子,而用方块表示相应结点的子树,下方数值代表该子树的高度。 

 

(2) RR平衡旋转(左单旋转)

由于在结点A的右孩子(R)的右子树(R)上插入了新结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要一次向左的旋转操作。将A的右孩子B向左上旋转代替A成为根结点,将A结点向左下旋转成为B的左子树的根结点,而B的原左子树则作为A结点的右子树.

 

(3) LR平衡旋转(先左后右旋转)

由于在A 的左孩子(L)的右子树(R)上插入新结点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先左旋转后右旋转。先将A结点的左孩子B的右子树的根结点C向左上旋转提升到B结点的位置,然后把该C结点向右上旋转提升到A结点的位置.

 

 (4)RL平衡旋转(先右后左双旋转)

 由于在A的右孩子(R)的左子树(L)上插入新结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先右旋转后左旋转。先将A结点的右孩子B的左子树的根结点C向右上旋转提升到B结点的位置,然后把该C结点向左上旋转提升到A结点的位置.

  

 1.定义结构体

typedef struct TreeNode
{
	int data;//定义数据域 
	int height;//定义高度 
	struct TreeNode *lchild;//左孩子 
	struct TreeNode *rchild;//右孩子 
}TreeNode;

 2.获取结点高度

int getHeight(TreeNode *node)
{
	return node ? node->height : 0;//判断node是否为空,为空返回0,不为空返回高度 
}

 3.取最大值

int max(int a,int b)
{
	return a > b ? a : b;
}

 4.RR平衡旋转(向左旋转一次)

void rrRotation(TreeNode *node,TreeNode **root)
{/*参数一node:代表该结点
参数二root:代表父结点结点*/
	TreeNode *temp = node->rchild;//右孩子保存给中间指针 
	node->rchild = temp->lchild;//node的左孩子赋值给node的右孩子 
	temp->lchild = node;//node代替node的左孩子 
	node->height = max(getHeight(node->lchild),getHeight(node->rchild))+1;//最大值加一 
	temp->height = max(getHeight(temp->lchild),getHeight(temp->rchild))+1;
	*root = temp;
}

5.LL平衡旋转(向右旋转一次)

void llRotation(TreeNode *node,TreeNode **root)
{/*参数一node:代表该结点
参数二root:代表父结点结点*/
	TreeNode *temp = node->lchild;
	node->lchild = temp->rchild;
	temp->rchild = node;
	node->height = max(getHeight(node->lchild),getHeight(node->rchild))+1;
	temp->height = max(getHeight(temp->lchild),getHeight(temp->rchild))+1;
	*root = temp;
}

 6.建立平衡二叉树

void avlInsert(TreeNode **T,int data)
{/*第一个参数**T:双重解引用,用于更改T中的值
第二个参数data:用于传递元素并比较大小*/
	if(*T==NULL)//首先判断该结点是否为空,是空结点则新建结点并初始化
	{
		*T = (TreeNode*)malloc(sizeof(TreeNode));//申请内存空间 
		(*T)->data = data;//写入数据
		(*T)->height = 0;//高度初始化为0 
		(*T)->lchild = NULL;//左孩子初始为空
		(*T)->rchild = NULL;//右孩子初始为空 
	}
	else if(data<(*T)->data)//data小于当前结点值 
	{
		avlInsert(&(*T)->lchild,data);//要插入的元素比结点内的元素小,则往左子树走
		//拿到当前左右子树的高度 
		int lHeight = getHeight((*T)->lchild);
		int rHeight = getHeight((*T)->rchild);
		if(lHeight-rHeight==2)//判断二叉树是否失衡 
		{//判断高度差 
			if(data<(*T)->lchild->data)//要插入的元素小于当前结点左孩子的元素 
			{//LL型  
				llRotation(*T,T);//右旋一次	
			}
			else
			{//LR型 
				rrRotation((*T)->lchild,&(*T)->lchild);//先左旋 
				llRotation(*T,T);//后右旋 
			}			
		}
	}
	else if(data>(*T)->data)//data大于当前结点值 
	{
		avlInsert(&((*T)->rchild),data);//要插入的元素比结点内的元素大,则往右子树走
		//拿到当前左右子树的高度 		
		int lHeight = getHeight((*T)->lchild);
		int rHeight = getHeight((*T)->rchild);
		if(rHeight-lHeight==2)//判断二叉树是否失衡 
		{//判断高度差 
			if (data>(*T)->rchild->data)
			{//RR型 
				rrRotation(*T,T);//左旋一次 
			}
			else
			{//RL型 
				llRotation((*T)->rchild,&(*T)->rchild);//先右旋 
				rrRotation(*T,T);//后左旋 
			} 
		}
	}
	(*T)->height = max(getHeight((*T)->lchild),getHeight((*T)->rchild))+1;
}

7.前序遍历(根左右)

void preOrder(TreeNode *T)
{
	if(T)
	{
		printf("%d ",T->data);//输出根结点
		preOrder(T->lchild);//递归遍历左子树
		preOrder(T->rchild);//递归遍历右子树
	}
}

8.主函数

int main()
{
	TreeNode *T = NULL;//初始树根结点 
	int nums[5] = {1,2,3,4,5};
	int i;
	for(i=0;i<5;i++)
		avlInsert(&T,nums[i]);//构造平衡二叉树 
	preOrder(T);
	printf("\n");
	return 0;
}

 完整代码:

#include <stdio.h>
#include <stdlib.h>
/*定义结构体*/
typedef struct TreeNode
{
	int data;//定义数据域 
	int height;//定义高度 
	struct TreeNode *lchild;//左孩子 
	struct TreeNode *rchild;//右孩子 
}TreeNode;
/*获取结点高度*/
int getHeight(TreeNode *node)
{
	return node ? node->height : 0;//判断node是否为空,为空返回0,不为空返回高度 
}
/*取最大值*/
int max(int a,int b)
{
	return a > b ? a : b;
}
/*RR平衡旋转(向左旋转一次)*/
void rrRotation(TreeNode *node,TreeNode **root)
{/*参数一node:代表该结点
参数二root:代表父结点结点*/
	TreeNode *temp = node->rchild;//右孩子保存给中间指针 
	node->rchild = temp->lchild;//node的左孩子赋值给node的右孩子 
	temp->lchild = node;//node代替node的左孩子 
	node->height = max(getHeight(node->lchild),getHeight(node->rchild))+1;//最大值加一 
	temp->height = max(getHeight(temp->lchild),getHeight(temp->rchild))+1;
	*root = temp;
}
/*LL平衡旋转(向右旋转一次)*/
void llRotation(TreeNode *node,TreeNode **root)
{/*参数一node:代表该结点
参数二root:代表父结点结点*/
	TreeNode *temp = node->lchild;
	node->lchild = temp->rchild;
	temp->rchild = node;
	node->height = max(getHeight(node->lchild),getHeight(node->rchild))+1;
	temp->height = max(getHeight(temp->lchild),getHeight(temp->rchild))+1;
	*root = temp;
}
/*建立平衡二叉树*/
void avlInsert(TreeNode **T,int data)
{/*第一个参数**T:双重解引用,用于更改T中的值
第二个参数data:用于传递元素并比较大小*/
	if(*T==NULL)//首先判断该结点是否为空,是空结点则新建结点并初始化
	{
		*T = (TreeNode*)malloc(sizeof(TreeNode));//申请内存空间 
		(*T)->data = data;//写入数据
		(*T)->height = 0;//高度初始化为0 
		(*T)->lchild = NULL;//左孩子初始为空
		(*T)->rchild = NULL;//右孩子初始为空 
	}
	else if(data<(*T)->data)//data小于当前结点值 
	{
		avlInsert(&(*T)->lchild,data);//要插入的元素比结点内的元素小,则往左子树走
		//拿到当前左右子树的高度 
		int lHeight = getHeight((*T)->lchild);
		int rHeight = getHeight((*T)->rchild);
		if(lHeight-rHeight==2)//判断二叉树是否失衡 
		{//判断高度差 
			if(data<(*T)->lchild->data)//要插入的元素小于当前结点左孩子的元素 
			{//LL型  
				llRotation(*T,T);//右旋一次	
			}
			else
			{//LR型 
				rrRotation((*T)->lchild,&(*T)->lchild);//先左旋 
				llRotation(*T,T);//后右旋 
			}			
		}
	}
	else if(data>(*T)->data)//data大于当前结点值 
	{
		avlInsert(&((*T)->rchild),data);//要插入的元素比结点内的元素大,则往右子树走
		//拿到当前左右子树的高度 		
		int lHeight = getHeight((*T)->lchild);
		int rHeight = getHeight((*T)->rchild);
		if(rHeight-lHeight==2)//判断二叉树是否失衡 
		{//判断高度差 
			if (data>(*T)->rchild->data)
			{//RR型 
				rrRotation(*T,T);//左旋一次 
			}
			else
			{//RL型 
				llRotation((*T)->rchild,&(*T)->rchild);//先右旋 
				rrRotation(*T,T);//后左旋 
			} 
		}
	}
	(*T)->height = max(getHeight((*T)->lchild),getHeight((*T)->rchild))+1;
}

/*前序遍历(根左右)*/
void preOrder(TreeNode *T)
{
	if(T)
	{
		printf("%d ",T->data);//输出根结点
		preOrder(T->lchild);//递归遍历左子树
		preOrder(T->rchild);//递归遍历右子树
	}
}
int main()
{
	TreeNode *T = NULL;//初始树根结点 
	int nums[5] = {1,2,3,4,5};
	int i;
	for(i=0;i<5;i++)
		avlInsert(&T,nums[i]);//构造平衡二叉树 
	preOrder(T);
	printf("\n");
	return 0;
}

 运行结果:

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/591660.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【源码解析】流控框架Sentinel源码深度解析

前言 前面写了一篇Sentinel的源码解析&#xff0c;主要侧重点在于Sentinel流程的运转原理。流控框架Sentinel源码解析&#xff0c;侧重点在整个流程。该篇文章将对里面的细节做深入剖析。 统计数据 StatisticSlot用来统计节点访问次数 SpiOrder(-7000) public class Statis…

PCL 改进点云双边滤波算法

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 我们先来回顾一下之前该算法的计算过程,在二维图像领域中,双边滤波算法是通过考虑中心像素点到邻域像素点的距离(一边)以及像素亮度差值所确定的权重(另一边)来修正当前采样中心点的位置,从而达到平滑滤波效果。…

PHPMySQL基础(五):模拟登录后跳转+会话存储功能实现

PHP&MySQL基础&#xff08;一&#xff09;:创建数据库并通过PHP进行连接_长风沛雨的博客-CSDN博客 PHP&MySQL基础&#xff08;二&#xff09;:通过PHP对MySQL进行增、删、改、查_长风沛雨的博客-CSDN博客 PHP&MySQL基础&#xff08;三&#xff09;:处理查询SQL返…

一图看懂 tqdm 模块:一个可在循环和命令行中使用的快速、可扩展的进度条,资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 tqdm 模块&#xff1a;一个可在循环和命令行中使用的快速、可扩展的进度条&#xff0c;资料整理笔记&#xff08;大全&#xff09; &#x1f9ca;摘要&#x1f9ca;模块图&…

软考高级架构师笔记-5计算机网络

目录 1. 前言 & 考情分析2. 网络功能和分类2.1 通信技术3. OSI七层模型及协议3. 1 局域网和广域网协议3. 2 协议3. 3 交换技术、路由、传输介质4 IP地址5 网络存储技术6 其它考点8. 结语1. 前言 & 考情分析 前文回顾: 软考高级架构师笔记-1计算机硬件软考高级架构师笔…

chatgpt赋能python:Python中未定义变量的默认值

Python中未定义变量的默认值 在Python编程中&#xff0c;有时候我们会使用未经定义的变量。如果这些变量没有被定义&#xff0c;那么它们将没有任何值。在这篇文章中&#xff0c;我们将讨论Python中未定义变量默认值的问题&#xff0c;并深入研究为什么这些默认值如此重要。 …

华为OD机试真题B卷 Java 实现【寻找关键钥匙】,附详细解题思路

一、题目描述 小强正在参加《密室逃生》游戏&#xff0c;当前关卡要求找到符合给定 密码K&#xff08;升序的不重复小写字母组成&#xff09;的箱子&#xff0c;并给出箱子编号&#xff0c;箱子编号为1~N。 每个箱子中都有一个字符串s&#xff0c;字符串由大写字母&#xff0…

改进YOLOv5,利用HRNet高分辨率特征金字塔的全新物体检测突破

目录 一、介绍1、物体检测的背景与重要性2、HRNet和YOLOv5的概述&#xff08;1&#xff09;HRNet的概述&#xff08;2&#xff09;YOLOv5的概述 二、HRNet的架构1、HRNet的基本单元2、HRNet的高分辨率特征金字塔3、HRNet的体系结构4、HRNet的特点5、HRNet的局限性 三、YOLOv5的…

chatgpt赋能python:Python中转化为列表的详细介绍

Python中转化为列表的详细介绍 Python是一门高级编程语言&#xff0c;它使用起来简单易学&#xff0c;被广泛应用于大数据处理、科学计算、机器学习等领域。在Python编程中&#xff0c;列表是一种非常重要的数据结构&#xff0c;它允许我们存储和操作一组数据&#xff0c;并且…

jenkins —— pipeline基础语法与示例

一、Jenkins介绍 二、Jenkins Pipeline介绍 Jenkins Pipeline总体介绍 1.Pipeline 是Jenkins 2.X核心特性&#xff0c;帮助Jenkins实现从CI到CD与DevOps的转变 2.Pipeline 简而言之&#xff0c;就是一套运行于Jenkins上的工作流框架&#xff0c;将原本独立 运行于单个或者多个…

GPT-4 的 6 个最佳使用场景

https://www.howtogeek.com/884077/best-uses-for-chatgpt-4/ 作者&#xff1a;SYDNEY BUTLER 无论是在 ChatGPT 中还是通过 API&#xff0c;对 OpenAI 的 GPT-4 模型的访问比 GPT-3.5 限制更多。这意味着你需要慎重考虑在何种情况下使用 GPT-4&#xff0c;并选择性地将最适合…

浙大知识图谱基础:学习笔记

0 基础知识 知识图谱中&#xff0c;知识的结构化表示主要有符号表示和向量表示两类方法。符号表示包括&#xff1a;一阶谓词逻辑&#xff0c;语义网络&#xff0c;描述逻辑和框架系统等。当前主要采用基于图的符号化知识表示&#xff0c;最常用的是有向标记图。 有向标记图分为…

SpringBoot统一功能处理(统一处理用户登陆权限验证、统一异常处理以及统一数据返回格式)

目录 1. SpringBoot统一功能处理简介 2. 统一处理用户登陆验证 2.1 原生SpringAOP实现统一登陆验证的问题 2.2 Spring拦截器实现用户统一登陆验证 2.3 扩展: 统一访问前缀添加 3. 统一异常处理 4. 统一数据返回格式 4.1 统一数据返回格式的必要性 4.2 实现统一数据返…

C++ vector类成员函数介绍

目录 &#x1f914;vector模板介绍&#xff1a; &#x1f914;特点&#xff1a; &#x1f914;vector的成员函数&#xff1a; &#x1f50d;vector构造函数&#xff1a; &#x1f50d;vector赋值函数 &#x1f50d;vector容器的判断函数 resize函数的重点内容&#xff1a; …

chatgpt赋能python:Python中的并:优化代码执行效率的利器

Python中的并&#xff1a;优化代码执行效率的利器 Python作为一种优秀的编程语言&#xff0c;被广泛使用于各种各样的项目中。然而&#xff0c;随着程序的不断扩张&#xff0c;代码的复杂度日益增加&#xff0c;执行效率也愈加遇到了严峻的挑战。在这种情况下&#xff0c;Pyth…

Linux系统下imx6ull QT编程—— Ubuntu 下编写程序(一)

Linux QT编程 文章目录 Linux QT编程前言一、C简介二、C环境设置1.安装编译 C 语言和 C的环境。2.创建文件编写代码3.编译运行代码 总结 前言 绍在 Ubuntu 在终端窗口下使用 vi/vim 编辑一个 C源文件。通过编写最简单的示例“Hello,World QCX”。 一、C简介 C &#xff08;c…

【分布式应用】ELK企业级日志分析系统

一、ELK 简介 ELK平台是一套完整的日志集中处理解决方案&#xff0c;将 ElasticSearch、Logstash 和 Kiabana 三个开源工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 1.1 ELK各组件介绍 ElasticSearch&#xff1a; 是基于Lucene&#xff08;一个…

Scala初识

1.scala简介 是一种多范式的编程语言&#xff0c;其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台&#xff08;Java虚拟机&#xff09;并兼容现有的Java程序。 scala特点 1.Scala是面向对象的 Scala是一种纯粹的面向对象语言&#xff0c;每一个…

Node.js 中的代码调试

目录 1、启用 Inspector 2、安全隐患 3、Inspector 客户端 4、启用远程调试的情形 5、以前的Debugger 1、启用 Inspector 当使用 --inspect 开关时&#xff0c;Node.js 进程开始侦听调试客户端&#xff0c;默认情况下侦听 127.0.0.1:9229 的域名和端口号&#xff1b;每个…

华为OD机试真题B卷 Java 实现【Linux 发行版的数量】,附详细解题思路

一、题目描述 Linux 操作系统有多个发行版&#xff0c;distrowatch.com 提供了各个发行版的资料。这些发行版互相存在关联&#xff0c;例如 Ubuntu 基于 Debian 只开发而 Mint 又基于 Ubuntu 开发&#xff0c;那么我们认为 Mint 同 Debian 也存在关联。 发行版集是一个或多个…