二叉平衡树

news2025/1/18 18:47:11

一直想深入的研究一下,并手写平衡二叉树的插入、删除代码。

二叉树是动态查找的典范,但在极限情况下,二叉树的查找效果等同于链表,而平衡二叉树可以完美的达到 log ⁡ 2 n \log_2 n log2n

AVL简称平衡二叉树,缩写为BBST,由苏联数学家 Adelse-Velskil 和 Landis 在 1962 年提出。

例子:

将17,9,2,12,14,26,33,15,40,23,25一次插入到一棵初始化为空的AVL树中,画出该二叉平衡树。

解:过程和结果如下图所示。

在这里插入图片描述

所谓平衡二叉树,就是指二叉树的左、右子树的深度差不超过2。每当超过时,需要对二叉树的失衡节点进行平衡。

BBST用两个整数来表示左右子树的深度,前面一个表示左子树的层数,右边一个代表右子树的层数。

调整时,首先需要找到要平衡的节点。找到调整节点后,处理的方法有4种:

上图中圆标号1的是左-左结构,标号2的是左-右结构,标号3的是右-右,标号4的是右-左结构,这4种结构的处理方式各有不同。

  1. 左-左结构,即(2,1)结构

中间节点当作父节点,最上面的节点当作右节点,最下边节点当作左节点

  1. 左-右结构,即(2,-1)结构

最下面节点当作父节点,父节点当作右节点,中间节点当作左节点

  1. 右-右结构,即(-2,-1)结构

中间节点当作父节点,最上面的节点当作左节点,最下边节点当作右节点

  1. 右-左结构,即(-2,1)结构

最下面节点当作父节点,最上面节点当作左节点,中间节点当作右节点

编程中,计算左、右子树深度的代码如下:


int deep(BBST* b) {
	if (b == 0)
	{
		return 0;
	}

	int ld =  deep(b->lchild);
		
	int rd = deep(b->rchild) ;
	
	return ld > rd ? ld + 1 : rd + 1;
}

有了上面的理论和编程基础,我们可以慢慢的调试并手动写出平衡二叉树的插入代码:


int BBSTree::insert(ELEMENT* e) {
	if (mTree == 0)
	{
		mTree = newnode(e);
		mSize = 1;
		return 1;
	}

	BBST* t = mTree;

	BBST* tc = 0;
	Stack s;

	ELEMENT elem;

	while (1) {
		if (e->e == t->data.e) {
			return 0;
		}
		else if (e->e > t->data.e)
		{
			if (t->rchild == 0)
			{
				tc = newnode(e);
				tc->parent = t;
				t->rchild = tc;
				mSize++;
				break;
			}
			else {			
				elem.e = (unsigned long long)t;
				s.push((ELEMENT*)&elem);

				t = t->rchild;				
			}
		}
		else {
			if (t->lchild == 0)
			{
				tc = newnode(e);
				tc->parent = t;

				t->lchild = tc;
				mSize++;
				break;
			}
			else {
				elem.e = (unsigned long long)t;
				s.push((ELEMENT*)&elem);

				t = t->lchild;		
			}
		}
	}

	while (s.isEmpty() == 0) {

		s.pop(&elem);
		BBST* b = (BBST*)elem.e;
		b->ld = deep(b->lchild);
		b->rd = deep(b->rchild);

		t->ld = deep(t->lchild);
		t->rd = deep(t->rchild);

		int high_diff = b->ld - b->rd;
		int low_diff = t->ld - t->rd;
		if(high_diff == 2 && low_diff == 1)
		{
			BBST* f = (BBST*)b->parent;
			if (f&&f->lchild == b)
			{
				f->lchild = t;
			}
			else if (f&&f->rchild == b)
			{
				f->rchild = t;
			}
			BBST* old_tr = t->rchild;
			t->rchild = b;
			b->parent = t;

			t->parent = f;
			b->rchild = old_tr;
		}
		else if (high_diff == 2 && low_diff == -1)
		{
			BBST* f = (BBST*)b->parent;
			if (f->lchild == b)
			{
				f->lchild = tc;
			}
			else if (f->rchild == b)
			{
				f->rchild = tc;
			}

			BBST* ltmp = t;
			while (ltmp->rchild)
			{
				ltmp = ltmp->rchild;
			}
			tc->lchild->parent = ltmp->rchild;
			ltmp->rchild = tc->lchild;

			BBST* rtmp = b;
			while (rtmp->lchild)
			{
				rtmp = rtmp->lchild;
			}
			tc->rchild->parent = rtmp->lchild;
			rtmp->lchild = tc->rchild;

			tc->rchild = b;
			tc->lchild = t;
			b->parent = tc;
			t->parent = tc;

			tc->parent = f;
		}
		else if (high_diff == -2 && low_diff == 1)
		{
			BBST* f = (BBST*)b->parent;
			if (f&&f->lchild == b)
			{
				f->lchild = tc;
			}
			else if (f&&f->rchild == b)
			{
				f->rchild = tc;
			}

			BBST* rtmp = b;
			while (rtmp && rtmp->rchild)
			{
				rtmp = rtmp->rchild;
			}
			tc->lchild->parent = rtmp->rchild;
			rtmp->rchild = tc->lchild;

			BBST* ltmp = t;
			while (ltmp && ltmp->lchild)
			{
				ltmp = ltmp->lchild;
			}
			tc->rchild->parent = ltmp->lchild;
			ltmp->lchild = tc->rchild;
			
			tc->rchild = t;
			tc->lchild = b;
			b->parent = tc;
			t->parent = tc;

			tc->parent = f;
		}
		else if (high_diff == -2 && low_diff == -1)
		{
			BBST* f = (BBST*)b->parent;
			if (f && f->lchild == b)
			{
				f->lchild = t;
			}
			else if (f && f->rchild == b)
			{
				f->rchild = t;
			}
			BBST* old_tl = t->lchild;
			t->lchild = b;
			b->parent = t;

			t->parent = f;
			b->lchild = old_tl;
		}
		tc = t;
		t = b;
	}

	return 0;
}

完整代码地址:
https://github.com/satadriver/dataStruct

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

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

相关文章

gpt1与bert区别

区别1:网络结构(主要是Masked Multi-Head-Attention和Multi-Head-Attention) gpt1使用transformer的decoder,单向编码,是一种基于语言模型的生成式模型,更适合生成下一个单词或句子 bert使用transformer的…

jenkins搭建文档

jenkins搭建文档 简介一、安装运行环境1、安装JDK环境1)查询自带的JDK2)卸载自带的JDK3)创建java文件夹并将jdk上传到该文件夹4)解压5)配置环境变量6)配置生效7)验证是否成功 2、安装maven环境1…

学习IO的第四天

作业 : 使用两个子进程完成两个文件的拷贝&#xff0c;子进程1拷贝前一半内容&#xff0c;子进程2拷贝后一般内容&#xff0c;父进程用于回收两个子进程的资源 #include <head.h>int main(int argc, const char *argv[]) {int rd -1;if((rdopen("./01_test.c&quo…

18、XSS——cookie安全

文章目录 1、cookie重要字段2、子域cookie机制3、路径cookie机制4、HttpOnly Cookie机制5、Secure Cookie机制6、本地cookie与内存cookie7、本地存储方式 一般来说&#xff0c;同域内浏览器中发出的任何一个请求都会带上cookie&#xff0c;无论请求什么资源&#xff0c;请求时&…

python 数据分析

数据分析 数据分析是指用适当的方法对收集的数据进行分析,提取有用信息并且形成结论. 广义的数据分析包括狭义的数据分析和数据挖掘.狭义的数据分析是指根据目的,采用对比分析,分组分析,交叉分析,回归分析等分析方法,对数据进行分析和处理,得到特征统计量的过程.数据挖掘是指…

【LLM_05】使用fastgpt搭建本地离线大语言模型(Chatglm3)问答+知识库平台

1、FastGPT 的知识库逻辑1.1 基础概念1.2 FastGPT知识库的导入1.3 FastGPT新建应用&#xff08;1&#xff09;创建一个知识库助手&#xff08;2&#xff09;创建一个python开发小助手 2、词向量比较测试2.1 开启词向量模型2.2 词向量模型性能比较 3、配置好之后的运行3.1 运行大…

python二维数组创建赋值问题:更改单个值却更改了所有项的值

test_list [] dic1 {} test_list [dic1 for _ in range(3)] ll [1, 2, 3]for i in range(3):test_list[i][value] ll[i]print(test_list)运行结果&#xff1a;每次赋值都更改了所有项 原因&#xff1a;python的二位数据创建方式就是这样&#xff0c;官方文档中有描述Wha…

数据结构初阶之二叉树性质练习与代码练习

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 数据结构初阶 Linux 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力,共赴大厂。 目录 1.前言 2.性质练习 3…

嵌入式学习---ARM中断控制系统

目录 外部事件与CPU的交互方式查询方式中断方式 什么是中断源S3C2440支持60个中断源FIQ和IRQ 中断处理流程将外设中断通知给CPUSUBSRCPND寄存器INTSUBMSK寄存器SRCPND寄存器INTMSK寄存器INTMOD寄存器INTPND寄存器 硬件中断处理是实时系统设计的最重要、最关键的问题。 外部事件…

Ubuntu22.04通过Maas和Juju部署openstack charm

目录 官方文档材料准备软件硬件 模板机和虚拟网络安装MAAS官方文档MAAS节点配置安装MAAS浏览器登录MAAS进行配置 激活DHCP 官方文档 https://docs.openstack.org/project-deploy-guide/charm-deployment-guide/2023.1/ 这是一个通过Maas面板即可部署openstack的方式&#xff0…

CTF特训日记day7

复现华为杯研究生国赛的adv_lua题目 从题目描述来看&#xff0c;漏洞应该和bytearray相关 用IDA逆向一下然后直接字符串搜索bytearray 只有这里有bytearray字样&#xff0c;继续查找交叉引用&#xff1a; 可以看到一系列方法&#xff0c;显然都是为bytearray所注册的吗&am…

smarty模版 [BJDCTF2020]The mystery of ip 1

打开题目 点击flag给了我们一个ip 点击hint&#xff0c;查看源代码处告诉了我们要利用这个ip bp抓包&#xff0c;并添加X-Forward-For头 所以这道题是XFF可控 本来联想到XFF漏洞引起的sql注入&#xff0c;但是我们无论输入什么都会正常回显&#xff0c;就联想到ssti注入 我们…

区块链密码学:基础知识、应用与未来发展

一、引言 区块链技术&#xff0c;作为一种分布式、去中心化的数据管理方式&#xff0c;密码学在其安全性和可靠性方面发挥着至关重要的作用。本文将详细介绍区块链密码学的基础知识、应用以及未来发展趋势。 二、区块链密码学基础知识 区块链密码学是区块链技术的核心组成部分…

React面试题(1)

1、什么是React&#xff1f; React是一个用于构建用户界面的JavaScript库。 2、React的特点是什么&#xff1f; React的主要特点包括&#xff1a; 组件化虚拟DOM单向数据流JSX语法高效的性能生态系统丰富 3、什么是JSX&#xff1f; JSX是一种JavaScript的语法扩展&#x…

2023年12月实时获取地图边界数据方法,省市区县街道多级联动【附实时geoJson数据下载】

首先&#xff0c;来看下效果图 在线体验地址&#xff1a;https://geojson.hxkj.vip&#xff0c;并提供实时geoJson数据文件下载 可下载的数据包含省级geojson行政边界数据、市级geojson行政边界数据、区/县级geojson行政边界数据、省市区县街道行政编码四级联动数据&#xff0…

Linux shell编程学习笔记33:type 命令

目录 0 引言1 type 命令的功能和格式 1.1 type命令的功能1.2 type 命令的格式2 type命令用法实例 2.1用type命令查看shell内置命令&#xff08;以echo命令为例&#xff09;2.2 用type命令查看别名&#xff08;以ls命令为例&#xff09;2.3 用type命令同时查看shell内置命令和别…

Ros智行mini,opencv,Gmapping建图,自主导航auto_slam,人脸识别,语音控制

功能 一、Gmapping建图 二、自主导航 起始点 、终点 三、人脸识别 四、语音控制 完成任务: 机器人先建图 建完图后给出目标点&#xff0c;机器人就可以完成调用自主导航走到目标点&#xff0c;期间会调用激光雷达扫描局部环境来进行自主避障&#xff0c;到达终点后进行语音…

UVM建造测试用例

&#xff08;1&#xff09;加入base_test 在一个实际应用的UVM验证平台中&#xff0c;my_env并不是树根&#xff0c;通常来说&#xff0c;树根是一个基于uvm_test派生的类。真正的测试用例都是基于base_test派生的一个类。 class base_test extends uvm_test;my_env e…

rpm安装gitlab

1.rpm包下载 https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/ 2.进行安装 rpm -ivh gitlab-ce-15.9.7-ce.0.el7.x86_64.rpm --nodeps --force 3.配置访问地址 vim /etc/gitlab/gitlab.rb 4.重新加载配置以及重启服务 gitlab-ctl reconfiguregitlab-ctl resta…

指针(进阶)

指针进阶&#xff1a; 通过指针基础我们已经了解了指针&#xff0c;这篇文章我们会举大量的例子&#xff0c;使我们对指针透彻理解&#xff0c;我们下来看一段代码&#xff1a; int main() {char a[] "ab";char* pc a;printf("%c\n", *pc);printf("…