linux 自平衡AVL树

2023-05-16

简介

仔细观察BST会发现,虽然它有良好的“搜索”特性,也就是可以利用其节点之前的大小关系,很容易地从根节点开始往下走找到我们所要的节点,但它无法保证这种搜索所需要的时间长短,因为建立BST时节点的随机性可能会导致它极其“不平衡”。
12
如上图所示是一棵二叉树,显然左轻右重,事实上这棵树已经退化成了一条链表,在这棵树中搜索某一个节点的时间复杂度和链表是一样的。

这种左轻右重或者左重右轻的长短腿的情形,就是所谓的不平衡;一棵树不平衡,那么他的搜索性能将会受到影响。具体来讲,当树保持平衡时,其搜索时间复杂度是O(log2n);当树退化成链表时,其搜索时间复杂度是O(n),其他情况下树的平均搜索时间复杂度就介于这两者之间。现在的目标就是要升级我们的BST,使之带有自平衡的特性,当它发现自己的左腿长或右腿长时,会及时调整,保持平衡。

要达到此目的,首先需要量化所谓的“平衡”,其严格数学定义是:在一棵树中,如果其任意一个节点的左右子树的高度差绝对值小于或等于1,那么它就是平衡的。

下面是AVL树的算法实现,包括了节点的创建、插入、删除、旋转等算法。

算法实现

head4tree.h

//
//  Description: 本文件为二叉树核心头文件。
//               任何使用本二叉树结构算法的程序,在包含本头文件之前
//               都需要将如下宏定义成二叉树节点需要表达的数据类型:
//
//                     TREE_NODE_DATATYPE
//
//               否则二叉树的节点数据类型一律默认为 int
//

#ifndef _HEAD4TREE_H_
#define _HEAD4TREE_H_

/*
 * Any application applying this linked-tree data structure should
 * define the macro "TREE_NODE_DATATYPE" before include this head
 * file, otherwise, the macro will be defined to 'int' as follow.
 *
*/

#ifndef TREE_NODE_DATATYPE
#define TREE_NODE_DATATYPE int
#endif

#include "commonheader.h"

#define MAX(a, b) ({ \
		typeof(a) _a = a; \
		typeof(b) _b = b; \
		(void)(&_a == &_b);\
		_a > _b? _a : _b; \
		})

typedef TREE_NODE_DATATYPE tn_datatype;


typedef struct _tree_node
{
	tn_datatype data;
	struct _tree_node *lchild;
	struct _tree_node *rchild;

#ifdef AVL
	int height;
#endif

}treenode, *linktree;

void pre_travel(linktree, void (*handler)(linktree));
void mid_travel(linktree, void (*handler)(linktree));
void post_travel(linktree, void (*handler)(linktree));
void level_travel(linktree, void (*handler)(linktree));

linktree bst_insert(linktree root, linktree new);
linktree bst_remove(linktree root, tn_datatype data);
linktree bst_find(linktree root, tn_datatype data);

#ifdef AVL
linktree avl_insert(linktree root, linktree new);
linktree avl_remove(linktree root, tn_datatype data);

linktree avl_rotate_left (linktree root);
linktree avl_rotate_right(linktree root);
linktree avl_rotate_leftright(linktree root);
linktree avl_rotate_rightleft(linktree root);

static int height(linktree root)
{
	return root==NULL ? 0 : root->height;
}
#endif

static linktree new_node(tn_datatype data)
{
	linktree new = malloc(sizeof(treenode));
	if(new != NULL)
	{
		new->data = data;
		new->lchild = NULL;
		new->rchild = NULL;

		#ifdef AVL
		new->height = 1;
		#endif

	}
	return new;
}

#endif

avl.c



//  Description: AVL算法实现代码



#include "head4tree.h"
#include "drawtree.h"

linktree avl_rotate_right(linktree root)
{
	linktree tmp = root->lchild;
	root->lchild = tmp->rchild;
	tmp->rchild = root;
	
	root->height = MAX(height(root->lchild), height(root->rchild)) + 1;
	tmp->height = MAX(height(tmp->lchild), root->height) + 1;

	return tmp;
}

linktree avl_rotate_left(linktree root)
{
	linktree tmp = root->rchild;
	root->rchild = tmp->lchild;
	tmp->lchild = root;
	
	root->height = MAX(height(root->lchild), height(root->rchild)) + 1;
	tmp->height = MAX(root->height, height(tmp->rchild)) + 1;

	return tmp;
}

linktree avl_rotate_leftright(linktree root)
{
	root->lchild = avl_rotate_left(root->lchild);
	return avl_rotate_right(root);
}

linktree avl_rotate_rightleft(linktree root)
{
	root->rchild = avl_rotate_right(root->rchild);
	return avl_rotate_left(root);
}

linktree avl_insert(linktree root, linktree new)
{
	if(root == NULL)
		return new;


	if(new->data < root->data)
		root->lchild = avl_insert(root->lchild, new);
	else if(new->data > root->data)
		root->rchild = avl_insert(root->rchild, new);
	else
	{
		printf("%d is already exist.\n", new->data);
	}


	if(height(root->lchild) - height(root->rchild) == 2)
	{
		if(new->data < root->lchild->data)
			root = avl_rotate_right(root);
		else if(new->data > root->lchild->data)
			root = avl_rotate_leftright(root);
	}

	else if(height(root->rchild) - height(root->lchild) == 2)
	{
		if(new->data > root->rchild->data)
			root = avl_rotate_left(root);
		else if(new->data < root->rchild->data)
			root = avl_rotate_rightleft(root);
	}


	root->height = MAX(height(root->lchild), height(root->rchild)) + 1;
	return root;
}

linktree avl_remove(linktree root, tn_datatype data)
{
	if(root == NULL)
		return NULL;

	if(data < root->data)
		root->lchild = avl_remove(root->lchild, data);
	else if(data > root->data)
		root->rchild = avl_remove(root->rchild, data);
	else
	{
		linktree p;

		if(root->lchild != NULL)
		{
			for(p=root->lchild; p->rchild!=NULL; p=p->rchild){;}
			root->data = p->data;
			root->lchild = avl_remove(root->lchild, p->data);
		}
		else if(root->rchild != NULL)
		{
			for(p=root->rchild; p->lchild!=NULL; p=p->lchild){;}
			root->data = p->data;
			root->rchild = avl_remove(root->rchild, p->data);
		}
		else
		{
			free(root);
			return NULL;
		}
	}

	if(height(root->lchild) - height(root->rchild) == 2)
	{
		if(height(root->lchild->rchild)-height(root->lchild->rchild) == 1)
			root = avl_rotate_leftright(root);
		else
			root = avl_rotate_right(root);
	}
	else if(height(root->rchild) - height(root->lchild) == 2)
	{
		if(height(root->rchild->lchild)-height(root->rchild->rchild) == 1)
			root = avl_rotate_rightleft(root);
		else
			root = avl_rotate_left(root);
	}

	root->height = MAX(height(root->lchild), height(root->rchild)) + 1;
	return root;
}

int main(void)
{
	linktree root = NULL;

	printf("输入大于0的数插入节点\n");
	printf("输入小于0的数删除节点\n");
	printf("输入0退出程序\n");

	int n;
	while(1)
	{
		scanf("%d", &n);

		if(n > 0)
		{
			linktree new = new_node(n);
			root = avl_insert(root, new);
		}
		else if(n < 0)
		{
			root = avl_remove(root, -n);
		}
		else
			break;

		draw(root);
		system("firefox -new-tab *.html &");
	}
	system("rm *.html");

	return 0;
}

示例

直接使用上面的文件,上述的main函数实现了以下功能:
1、输入一个正整数,则插入该节点
2、输入一个负整数,则删除其绝对值对应的节点
3、输入0,退出程序
4、退出程序前在网页上画出该二叉树

运行效果如下:

zzc@zzc-virtual-machine:~/share/example/数据结构$ ./avl
输入大于0的数插入节点
输入小于0的数删除节点
输入0退出程序
1
2
3
4
54
5
8
6
2
2 is already exist.
8
8 is already exist.
9
10
0

在网页上显示该二叉树:
12

注意事项

1、上述示例程序中使用了draw函数,用于在网页上画出二叉树。
2、上述示例用到的源代码(一些头文件和c文件)放在以下博文中:
https://blog.csdn.net/gogo0707/article/details/124855232
3、AVL树也是BST树,所以查找某一个节点时直接使用BST查找算法即可

总结

本文介绍了AVL树的基本概念,进行了算法的实现,并通过示例程序演示了二叉树如何实现自平衡。
后续我有时间再慢慢补充有关AVL树的知识点和一些可能遇到的问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux 自平衡AVL树 的相关文章

  • Linux 中的无缓冲 I/O

    我正在写入大量的数据 这些数据数周内都不会再次读取 由于我的程序运行 机器上的可用内存量 显示为 空闲 或 顶部 很快下降 我的内存量应用程序使用量不会增加 其他进程使用的内存量也不会增加 这让我相信内存正在被文件系统缓存消耗 因为我不打算
  • 抑制 makefile 中命令调用的回显?

    我为一个作业编写了一个程序 该程序应该将其输出打印到标准输出 分配规范需要创建一个 Makefile 当调用它时make run gt outputFile应该运行该程序并将输出写入一个文件 该文件的 SHA1 指纹与规范中给出的指纹相同
  • 通过特定分隔符删除字符串

    我的文件中有几列 其中第二列有 分隔符 我想删除第二列中的第一个 第三个和第四个字符串 并将第二个字符串留在该列中 但我有正常的分隔符空间 所以我不知道 input 22 16050075 A G 16050075 A G 22 16050
  • GLIBCXX_3.4.26 未找到在 BeagleBone 上运行交叉编译的程序

    我有以下程序 include
  • 仅打印“docker-container ls -la”输出中的“Names”列

    发出时docker container ls la命令 输出如下所示 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a67f0c2b1769 busybox tail f dev
  • 如何在bash中使用jq从变量中包含的json中提取值

    我正在编写一个 bash 脚本 其中存储了一个 json 值 现在我想使用 Jq 提取该 json 中的值 使用的代码是 json val code lyz1To6ZTWClDHSiaeXyxg redirect to http examp
  • Linux中的定时器类

    我需要一个计时器来以相对较低的分辨率执行回调 在 Linux 中实现此类 C 计时器类的最佳方法是什么 有我可以使用的库吗 如果您在框架 Glib Qt Wx 内编写 那么您已经拥有一个具有定时回调功能的事件循环 我认为情况并非如此 如果您
  • chown:不允许操作

    我有问题 我需要通过 php 脚本为系统中的不同用户设置文件所有者权限 所以我通过以下命令执行此操作 其中 1002 是系统的用户 ID file put contents filename content system chown 100
  • fopen 不返回

    我在 C 程序中使用 fopen 以只读模式 r 打开文件 但就我而言 我观察到 fopen 调用没有返回 它不返回 NULL 或有效指针 执行在 fopen 调用时被阻止 文件补丁绝对正确 我已经验证过 并且不存在与权限相关的问题 任何人
  • 如何有效截断文件头?

    大家都知道truncate file size 函数 通过截断文件尾部将文件大小更改为给定大小 但是如何做同样的事情 只截断文件的尾部和头部呢 通常 您必须重写整个文件 最简单的方法是跳过前几个字节 将其他所有内容复制到临时文件中 并在完成
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • 尝试安装 LESS 时出现“请尝试以 root/管理员身份再次运行此命令”错误

    我正在尝试在我的计算机上安装 LESS 并且已经安装了节点 但是 当我输入 node install g less 时 出现以下错误 并且不知道该怎么办 FPaulMAC bin paul npm install g less npm ER
  • 如何在 Linux shell 中将十六进制转换为 ASCII 字符?

    假设我有一个字符串5a 这是 ASCII 字母的十六进制表示Z 我需要找到一个 Linux shell 命令 它将接受一个十六进制字符串并输出该十六进制字符串代表的 ASCII 字符 所以如果我这样做 echo 5a command im
  • 将 PDF 转换为 600dpi 的 TIFF 和 jpg 96 dpi

    我想使用 ImageMagick 从 Python 脚本将 pdf 转换为 600 dpi 的 tiff 和 96 dpi 的 jpg 我使用 imagemagick 命令行完成了这项任务 但我想使用python中的Imagemagick将
  • NPTL 和 POSIX 线程有什么区别?

    NPTL 和 POSIX 线程之间的基本区别是什么 这两者是如何演变的 POSIX 线程 pthread 不是一个实现 它是几个函数的 API 规范 纸上的标准 英文 其名称以pthread 以及定义在
  • 安装J语言的JQt IDE,出现错误

    我一直按照这里的说明进行操作 http code jsoftware com wiki System Installation Linux http code jsoftware com wiki System Installation L
  • 使用 sh 运行 bash 脚本

    我有 bash 脚本 它需要 bash 另一个人尝试运行它 sh script name sh 它失败了 因为 sh 是他的发行版中 dash 的符号链接 ls la bin sh lrwxrwxrwx 1 root root 4 Aug
  • 有谁知道在哪里定义硬件、版本和序列号。 /proc/cpuinfo 的字段?

    我想确保我的 proc cpuinfo 是准确的 目前它输出 Hardware am335xevm Revision 0000 Serial 0000000000000000 我可以在代码中的哪里更改它以给出实际值 这取决于 Linux 的
  • 如何确保应用程序在 Linux 上持续运行

    我试图确保脚本在开发服务器上保持运行 它会整理统计数据并提供网络服务 因此它应该会持续存在 但一天中有几次 它会因未知原因而消失 当我们注意到时 我们只需再次启动它 但这很麻烦 并且某些用户没有权限 或专有技术 来启动它 作为一名程序员 我
  • 如何更改 Apache 服务器的根目录? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何更改 Apache 服务器的文档根目录 我基本上想要localhost从 来 users spencer projects目录而不是

随机推荐

  • 深度卷积对抗生成网络(DCGAN)

    本文是参考文献 1 的论文笔记 卷积神经网络在有监督学习中的各项任务上都有很好的表现 xff0c 但在无监督学习领域 xff0c 却比较少 本文介绍的算法将有监督学习中的CNN和无监督学习中的GAN结合到了一起 在非CNN条件下 xff0c
  • 看图说话——CNN和LSTM的联合应用

    看图说话是深度学习波及的领域之一 其基本思想是利用卷积神经网络来做图像的特征提取 xff0c 利用LSTM来生成描述 但这算是深度学习中热门的两大模型为数不多的联合应用了 本文是参考文献 1 的笔记 xff0c 论文是比较早的论文 xff0
  • 机器学习经典书籍小结

    机器学习经典书籍小结 转载本博客请注明链接 xff1a http blog csdn net xinzhangyanxiang article details 9069045 博客第一篇文章 1 是转载的 xff0c 也算是开始写博客不经意
  • Microsoft Media foundation概述(附实例)

    Microsoft Media Foundation是微软新一代多媒体开发平台 xff0c 用以取代原来的Directshow xff0c 为了满足现在多媒体播放的高清晰 xff0c 高品质 xff0c 颜色管理 xff0c 以及充分利用硬
  • Dockerfile中 使用pip镜像源加速下载

    用dockerfile文件制作镜像 xff0c 提高pip下载速度 1 安装pip3 xff0c python3 RUN apt get update RUN apt get install y python3 5 RUN apt get
  • NVIDIA Jetson Nano主机的autoware的学习与demo运行-第7章-Autoware源码安装

    Autoware源码安装 建立workspace mkdir p autoware ai src cd autoware ai 这个是下载了一个名为autoware ai repos的文件 xff0c 是为了方便管理多个git库而开发 43
  • NVIDIA Jetson Nano主机的autoware的学习与demo运行-第8章-Autoware官方demo运行

    Autoware官方demo 个人学习者很少拥有齐全的传感器以及工控机 xff0c 所以我们可以用autoware ai官网提供的一些录制好的rosbag包及个人笔记本来跑些有趣的demo 安装了 Autoware 之后 xff0c 就可以
  • NVIDIA Jetson AGX Xavier主机刷机与SSD安装

    任务逻辑 当有个新的AGX主机到手上后 xff0c 主机是启动的是eMMC xff0c 大约30G存储 这个安装了系统后到后面随便弄一下就不够存储了 xff0c 所以我是想要在主机上安装一个SSD xff0c 然后将系统直接放到SSD上 x
  • 自平衡linux红黑树

    简介 实际应用中的自平衡搜索二叉树 xff0c 除了AVL之外 xff0c 红黑树也是备受宠爱 他不仅是linux中非线性结构的标准算法 xff0c 而且是Java中TreeMap TreeSet机制 C 43 43 中的STL这些经典工具
  • yolov3的训练(一)下载与训练

    darknet框架简介 https blog csdn net mao hui fei article details 113820303 AlexeyAB大佬的关于darknet的详细文档信息 https github com Alexe
  • yolov3的训练(五)darknet的VOC测试集和训练集以及训练前准备

    VOC测试集和训练集 同学们 xff0c 这个系列的文件不要直接就跟着我操作了 xff0c 因为这个是踩坑的记录 xff0c 不是教程 xff0c 我只是将整个流程记录下来 xff0c 让后面的同学操作的时候能够避开这些坑 xff0c 希望
  • yolov3的训练(七)使用darknet_ros框架进行识别与模型导入

    同学们 xff0c 这个系列的文件不要直接就跟着我操作了 xff0c 因为这个是踩坑的记录 xff0c 不是教程 xff0c 我只是将整个流程记录下来 xff0c 让后面的同学操作的时候能够避开这些坑 xff0c 希望你能将整个系列的操作流
  • ORB-SLAM2的布置(一)Pangolin的安装

    参考文件 ORB SLAM 2在github的官方流程 https github com raulmur ORB SLAM2 然后就是安装Pangolin 在 ORB SLAM 2 中那些很炫酷的实时建图画面是通过 Pangolin 实现的
  • ORB-SLAM2的布置(二)ORB-SLAM2的安装

    当在上一节中 xff0c Pangolin 安装成功后 xff0c 便可进行ORB SLAM2的安装 这里的普通模式是指直接运行编译之后的可执行文件 xff0c ROS 模式是以ROS机器人框架的形式执行 首先从 github 下载源文件
  • ORB-SLAM2的布置(四)ORB-SLAM2构建点云

    提要 高博的工作是对基本 ORB SLAM2 的扩展 xff0c 基本思想是为每个关键帧构造相应的点云 xff0c 然后依据从 ORB SLAM2 中获取的关键帧位置信息将所有的点云拼接起来 xff0c 形成一个全局点云地图 https g
  • ORB-SLAM2的布置(三)ORB-SLAM2的测试使用

    目标 在上一节 xff0c 我们完成了ORB SLAM2的编译与测试 xff0c 这一节使用完整的数据集进行测试 普通模式 这里的普通模式直接运行编译之后的可执行文件 单目摄像头 首先是单目摄像头 这里我们使用TUM数据集进行离线测试 去到
  • ORB-SLAM2的布置(五)使用 intel D435i 构建SLAM点云地图

    Intel RealSense SDK 2 0 是跨平台的开发套装 xff0c 包含了基本的相机使用工具如 realsense viewer xff0c 也为二次开发提供了丰富的接口 xff0c 包括 ROS xff0c python Ma
  • 阿里云ecs服务器(Ubuntu)配置图形界面并远程桌面连接

    1 登录阿里云后跳转到管理页面 xff0c 点击远程连接 xff08 如图1 xff09 2 选择Workbench远程连接登录进入到终端命令窗口 xff0c 首次登录需要设置实例密码 登录后界面如下 3 安装ubuntu桌面系统 执行下面
  • Windows Nodejs多版本使用

    一 遇到的问题 不同的项目使用的node版本不一致 xff0c 导致使用的时候 xff0c 安装依赖的时候冲突了 xff0c 从网上找了很多的方案 xff0c 解决起来也挺费劲的 xff1b 问题 xff1a 当一个项目使用低版本的时候 x
  • linux 自平衡AVL树

    简介 仔细观察BST会发现 xff0c 虽然它有良好的 搜索 特性 xff0c 也就是可以利用其节点之前的大小关系 xff0c 很容易地从根节点开始往下走找到我们所要的节点 xff0c 但它无法保证这种搜索所需要的时间长短 xff0c 因为