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

平衡二叉树的定义:

 为避免树的高度增长过快,降低二叉排序树的性能,规定在插入和删除二叉树结点时,要保证任意结点的左、右子树高度差的绝对值不超过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://xiahunao.cn/news/255898.html

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

相关文章

chatgpt赋能python:如何在Python中撤回输错的指令?

如何在Python中撤回输错的指令&#xff1f; 作为一名有10年Python编程经验的工程师&#xff0c;我们时常会遇到输错指令的情况。在Python中输错指令常常是不可避免的&#xff0c;特别是当你快速编写代码时。然而&#xff0c;如果你不知道如何撤回这些错误的指令&#xff0c;这…

手机备份到底备份什么

手机备份到底备份什么 文章目录 手机备份到底备份什么起因准备如何快速备份开始备份文件备份聊天记录备份图片备份软件备份 往期回顾 最后&#xff0c;点个关注不迷路 手机太卡了&#xff0c;换不起手机&#xff0c;所以就备份一下&#xff0c;刷一下 起因 手机开始卡了&#x…

华为云服务的使用方法详解--以照片备份与恢复为例

既然iPhone有iCloud&#xff0c;小米有小米云服务&#xff0c;华为当然也有自己的华为云服务。但是有些花粉可能还不知道华为云服务到底要怎么使用&#xff0c;今天小编就以照片的备份与恢复为例&#xff0c;跟大家说说华为云备份的使用方式。 一、什么是华为云备份 简单来说…

华为手机[助手]备份的db通讯录文件如何恢复到其他手机

华为手机[助手]备份的db通讯录文件如何恢复到其他手机 如果你是属于下面的情况分析需要的文件第一步最后一步结束 如果你是属于下面的情况 1.如果你使用华为手机并且用华为手机助手备份了&#xff0c;但是你想把文件恢复到其他手机上&#xff08;其他品牌的安卓手机或者苹果手…

chatgpt赋能python:Python中的按位取反

Python中的按位取反 Python中的按位取反是一种常见的操作&#xff0c;它可以让我们快速地对二进制的数字进行取反操作。在本文中&#xff0c;我们将介绍Python中的按位取反操作&#xff0c;并探讨它的用途和示例。 什么是按位取反 按位取反是一种将二进制数中的每一位进行反…

【Android取证篇】华为手机OTG备份密码重置教程

【Android取证篇】华为手机OTG备份密码重置教程 ​ 提取华为设备遇到OTG备份出来的数据信息软件无法正常解析时&#xff0c;排除数据提取不完整、软件设备等问题&#xff0c;可考虑重置华为的备份密码&#xff0c;重新备份数据再分析—【suy】 文章目录 【Android取证篇】华为…

华为手机MATE10所有分区备份与数据恢复方法

华为手机MATE10所有分区备份与数据恢复方法 作者&#xff1a;爱吃干锅牛肉的喵 时间2020-3-23 前言&#xff1a; 前段时间笔者手机的root权限出问题&#xff0c;误操作重破解ROOT权限导致数据全部wipe并且系统也坏了。没办法重刷机。因为重新刷机&#xff0c;分区表结构都变了…

华为手机备忘录资料备份

为什么80%的码农都做不了架构师&#xff1f;>>> [备份] ->选择备份 ->选择备份到SD卡还是内存卡 -> 选择需要备份的项目 ->确定 备忘录 在memo.db中,通过sqlite浏览器可以打开. 转载于:https://my.oschina.net/GMT/blog/855829

华为手机备份的通讯录是什么文件_手机怎么备份通讯录?华为手机备份方法大全...

原标题&#xff1a;手机怎么备份通讯录&#xff1f;华为手机备份方法大全 现在有很多人选择国产手机&#xff0c;而华为手机作为国产手机中的佼佼者&#xff0c;使用的人也有很多&#xff0c;今天我们就来聊聊会为手机里的备份。 1、本地备份 华为手机中自带有备份的功能&#…

C++实现sqlite单表增删改查的详细步骤

1.环境准备 coding之前需要先安装好C的集成开发环境&#xff0c; 我这里选择的是Visual Studio 2022&#xff0c;本来想使用CLion的&#xff0c; 但是破解太麻烦&#xff0c;懒得整了。 Visual Studio 2022 2.项目创建及编码 启动visual studio, 点击创建项目&#xff0c;选…

环境变量设置export 命令详解

环境变量通俗来讲&#xff0c;就是指定一个路径&#xff0c;编译工具或运行软件时&#xff0c;任务进程会按照设置的路径来搜索文件或使用工具。如果不设置环境变量&#xff0c;又想使用该条命令&#xff0c;则需要加上绝对路径&#xff0c;否则我们需要把文件复制到系统标准命…

centos7环境变量设置

目录 一、 环境变量概念 1、环境变量的含义 2、环境变量的分类 3、Linux环境变量 二、常用的环境变量 1、查看环境变量 1&#xff09;env命令&#xff1a;查看当前用户全部的环境变量。 2&#xff09;echo命令&#xff1a;查看当前用户全部的环境变量&#xff0c;符号$不…

chatgpt赋能python:Python中调换数据位置的方法

Python中调换数据位置的方法 在Python编程中&#xff0c;我们经常需要操作数据的位置&#xff0c;例如调换数组中的元素顺序、交换多个变量的值等。在本篇文章中&#xff0c;我们将介绍Python中调换数据位置的常用方法&#xff0c;并给出相应的代码示例。 1.使用临时变量交换…

jenkins —— pipeline基础语法与示例

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

SpringBoot调阿里云人脸识别人脸对比接口

开发工具&#xff1a;IDEA2019.3 开发框架&#xff1a;SpringBoot2.2 数据库&#xff1a;Mysql 接口测试工具:swagger 阿里云demo如下 和我之前调OCR身份证识别类似&#xff0c;也有StringUtils工具类&#xff0c;和一些依赖&#xff0c;这个是需要的依赖 <?xml version…

Python 基于OpenCV+face_recognition实现人脸捕捉与人脸识别(照片对比)

1.安装包依赖 与上篇通过摄像头动态识别人脸一样&#xff0c;先下载好opencv-python、face-recognition&#xff0c;这里因为使用的是照片对比的方式&#xff0c;特意使用tkinter画了一个简单的GUI方便操作。 在python 3以上版本tkinter是环境自带的&#xff0c;所以这里不需…

使用百度AI接口进行人脸对比(Python SDK V3版本实现)

一.安装人脸识别 Python SDK 首先在当前的python环境中使用pip install baidu-aip安装人脸识别 Python SDK。 二.算法思路 1.首先通过python SDK中的AipFace类获取一个客户端对象。 from aip import AipFace""" 你的APPID&#xff0c;API_KEY和SECRET_KEY &q…

测试相貌相似度的软件,快乐相似脸 - 测试你们之间的长相相似度

快乐相似脸 - 测试你们之间的长相相似度 介绍 快乐相似脸 - 测试你们之间的长相相似度 快乐相似脸是一款用于测试两个人头像相似度的恶搞软件&#xff0c;无论你们是好朋友、基友、情侣或者拉拉&#xff0c;测一下你们俩到底长得像不像吧&#xff0c;看看你们缘分如何&#xff…

图像相似度对比分析软件,图像相似度对比分析法

有什么可以对比两张图片得出相似度的软件。 谷歌人工智能写作项目&#xff1a;神经网络伪原创 图像怎么进行比对 有什么软件可以把两张照片进行对比 查看相似度 1、Mix滤镜大师。IX滤镜大师免费提供将近200款默认滤镜&#xff0c;包括景深滤镜&#xff0c;散景滤镜&#xff…

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

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