平衡二叉树的实现(包含旋转)

news2025/1/13 15:30:54

平衡二叉树是子啊二叉排序树的基础上建立的,他的概念就是这棵树中的任意节点的平衡因子都必须要大于1或是小于-1。平衡因子就是这个节点的左子树高度减右子树高度所得到的差。那么,它有什么优点呢?为什要在二叉排序树的基础上来建立这个平衡二叉树呢?我们来看下面的这幅图:

 在这个二叉排序树中,如果要查一个节点的数据域,那么它的时间复杂度是多少呢?我们知道,在学时间复杂度的时候,我们一般都是根据最坏的结果来计算的,那么,它的最差的时间复杂度用大O表法,是不是就是O(n),但是如果这是一个平衡二叉树的话,那么,这个平衡二叉树的搜索时间就是O(log n)。为什么呢?我们可以看下面的这幅图:

如果是平衡二叉树的话,这个树就会是这个样子。是不是就会很容易的找到了呢?这里有关于旋转,下面会说。这个就是关于平衡二叉树的好处。那么,还是老样子,究竟该怎么样实现他呢?接下来就来代码实现了:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef struct tree
{
	int val;
	struct tree* left;
	struct tree* right;
}tree;
void push(tree** root, int x);
void adjust(tree** root, int x);
tree* find(tree* root, int x);
void print(tree* root);
#define _CRT_SECURE_NO_WARNINGS 1
#include"tree.h"
void push(tree** root, int x)
{
	assert(root);
	if (*root == NULL)
	{
		tree* new = (tree*)malloc(sizeof(tree));
		assert(new);
		new->left = NULL;
		new->right = NULL;
		new->val = x;
		*root = new;
	}
	else
	{
		if (x < (*root)->val)
			push(&(*root)->left, x);
		else
			push(&(*root)->right, x);
	}
}
static int high(tree* root)
{
	if (root == NULL)
		return 0;
	else
	{
		int left = high(root->left);
		int right = high(root->right);
		if (left >= right)
			return left + 1;
		else
			return right + 1;
	}
}
void adjust(tree** root, int x)
{
	assert(root);
	if (*root == NULL)
		return;
	else
	{
		int left = high((*root)->left);
		int right = high((*root)->right);
		int balance = left - right;
		//不平衡就旋转最小不平衡的子树
		if (balance > 1 || balance < -1)
		{
			if (x < (*root)->val)
			{
				//LL
				if (x < (*root)->left->val)
				{
					tree* cur = (*root)->left->right;
					tree* tem = (*root)->left;
					tem->right = *root;
					*root = tem;
					(*root)->right->left = cur;
				}
				else
				{
					//LR
					tree* cur = (*root)->left->right;
					tree* tem = (*root)->left;
					tree* last = cur->left;
					cur->left = tem;
					tem->right = last;
					(*root)->left = cur;
					tem = cur->right;
					cur->right = *root;
					last = cur->right;
					last->left = tem;
					*root = cur;
				}
			}
			else
			{
				if (x > (*root)->right->val)
				{
					//RR型
					tree* cur = (*root)->right;
					tree* tem = (*root)->right->left;
					cur->left = *root;
					*root = cur;
					(*root)->left->right = tem;
				}
				else
				{
					//RL型
					tree* cur = (*root)->right->left;
					tree* tem = (*root)->right;
					tree* last = cur->right;
					cur->right = tem;
					tem = cur->right;
					tem->left = last;
					(*root)->right = cur;
					last = cur->left;
					cur->left = *root;
					*root = cur;
					(*root)->left->right = last;
				}
			}
		}
		//平衡就继续遍历他的左右子树
		else
		{
			adjust(&(*root)->left, x);
			adjust(&(*root)->right, x);
		}
	}
}
tree* find(tree* root, int x)
{
	if (root == NULL)
		return NULL;
	if (x == root->val)
		return root;
	else
	{
		find(root->left, x);
		find(root->right, x);
	}
}
void print(tree* root)
{
	if (root == NULL)
		return;
	else
	{
		print(root->left);
		printf("%d->", root->val);
		print(root->right);
	}
}
#define _CRT_SECURE_NO_WARNINGS 1
#include "tree.h"
void test()
{
	tree* root = NULL;
	push(&root, 50);
	//adjust(&root, 50);
	push(&root, 55);
	//adjust(&root, 55);
	push(&root, 54);
	//adjust(&root, 54);
	push(&root, 46);
	//adjust(&root, 46);
	push(&root, 41);
	//adjust(&root, 41);
	push(&root, 48);
	//adjust(&root, 48);
	push(&root, 59);
	//adjust(&root, 59);
	push(&root, 60);
	//adjust(&root, 60);
	push(&root, 70);
	tree* ret = find(root, 59);
	tree* tem = find(root, 55);
	adjust(&ret, 70);
	tem->right = ret;
	print(root);
}
int main()
{
	test();
	return 0;
}

以上是我实现的代码,大体思想就是先按照普通的二叉排序树来建立一颗树,然后在检查不平衡的子树,然后再旋转。

旋转有四种情况:1.LL:就是插入的节点在当前节点的左子树的左孩子处,然后此时的思想就是旋转,此时的这个节点就是最小不平衡子树,我们把他的左孩子旋转,类似于下图:

就是这样,如果当前节点的左孩子有右子树,那么就要把他的右子树插入到旋转之后的左子树处,按照上图来说就是把44的右子树插入到旋转之后的50的左子树处。

2.RR:这个和LL型原理一样,就是旋转的方向不同而已,此时要注意,这里就不再多说。

3.LR:这个就是要把当前节点的左孩子的右孩子旋转到根节点的位置,具体如下图:

 

注意的是旋转的节点如果有左子树或是右子树,我们应该提前保存它,旋转之后在插入。

4.RL:这个和LR一样,也就是旋转的方向不同,思路是一样的。

好了,旋转的思想给大家说完,那么就是代码了,上面的代码是调试的时候可以清楚的看到,但是唯一不好的地方在于必须提前把最小不平衡子树找到,然后传入不平衡节点的地址,还有找到他的前驱,以方便旋转完成之后继续衔接。

最后,希望大家可以支持一下,谢谢!!!

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

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

相关文章

语音芯片排行榜,为何唯创知音WT588F语音芯片如此受欢迎

随着智能家居、智能玩具、智能机器人等领域的快速发展&#xff0c;语音芯片逐渐成为智能硬件的重要组成部分。在众多语音芯片中&#xff0c;唯创知音WT588F语音芯片备受关注&#xff0c;成为市场上备受欢迎的产品。那么&#xff0c;WT588F语音芯片具备哪些功能&#xff0c;为何…

您的云,您做主:Google Distributed Cloud Hosted 全面可用

近日&#xff0c;谷歌宣布Google 分布式云(GDC) 托管的全面可用性来扩展该产品组合&#xff0c;它支持具有最严格要求的客户的需求&#xff0c;包括机密、受限和绝密数据。 GDC Hosted 包括部署、操作、扩展和保护完整托管云所需的硬件、软件、本地控制平面和操作工具。此外&…

【高危】MySQL Server拒绝服务漏洞(CVE-2023-21912)

漏洞描述 MySQL是Oracle开源的关系型数据库管理系统。 MySQL Server 受影响版本存在拒绝服务漏洞&#xff0c;攻击者者无需身份验证可发送连接数据包导致MySQL Server 崩溃拒绝服务。官方未公布相关细节&#xff0c;可能由于对客户端设置字符集的处理不当&#xff0c;当客户端…

关于倾斜摄影超大场景的三维模型轻量化中的数据质量优化方法浅析

关于倾斜摄影超大场景的三维模型轻量化中的数据质量优化方法浅析 倾斜摄影超大场景的三维模型轻量化处理需要兼顾数据大小和渲染性能&#xff0c;同时保证模型的准确性和真实感。为了提高轻量化质量&#xff0c;可以从以下方面入手&#xff1a; 1、选择合适的轻量化算法和参数…

OpenCV实战5 车牌号识别

原文在这里&#xff0c;参考这个进行了改进 感觉学到了很多东西&#xff0c;便在这里作下笔记。 效果&#xff1a; 目录 一、知识点学习&#xff1a; 1. fstream 2. 形态学开操作与形态闭操作 2.1 第一个角度:消除较小的联通区域 vs 弥合较小的联通区域 2.2 第二个角度&…

【LeetCode】222.完全二叉树的节点数

1.问题 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在该层最左边的若干位…

【MySQL】存放页面的大池子——InnoDB的表空间

1 前置知识回顾 1.1 页面类型 InnoDB是以页为单位管理存储空间的。我们的聚簇索引&#xff08;也就是完整的表数据&#xff09;和其他的二级索引都是以B树的形式保存到表空间中&#xff0c;而B树中的节点就是数据页&#xff0c;这个数据页的类型名其实是 FIL_PAGE_INDEX。 除…

JS手撕代码系列【手写实现Promise.all】

Promise.all() 方法接收一个 Promise 对象数组作为参数&#xff0c;返回一个新的 Promise 对象。该 Promise 对象在所有的 Promise 对象都成功时才会成功&#xff0c;其中一个 Promise 对象失败时&#xff0c;则该 Promise 对象立即失败。 本篇博客将手写实现 Promise.all() 方…

初始 Ajax

文章目录 一、服务器的基本概念1、客户端与服务器2、url地址3、客户端与服务器的通信过程4、服务器对外提供资源5、资源的请求方式 二、初始 Ajax1、了解Ajax2、JQuery中的Ajax&#xff08;1&#xff09;$.get()函数的用法&#xff08;2&#xff09;$.post()函数的语法&#xf…

国民技术N32G430开发笔记(7)- Gpio EXTI中断的使用

GPIO EXTI中断的使用 1、N32G430C8L7_STB板卡带有三个用户按键&#xff0c;我们初始化key1 key2 按键&#xff0c;当按键按下时&#xff0c;在中断处理函数里输出我们的打印信息。 2、根据芯片手册上N32G430C8L7有24 条中断线&#xff0c;16条分配给GPIO使用&#xff0c;其余八…

中国移动发布COCA软硬一体片上计算架构,引领云计算市场下一个黄金十年

当前&#xff0c;数字经济发展已经成为改变全球竞争格局的关键力量&#xff0c;随着算力成为数字经济新引擎&#xff0c;算力规模持续增长&#xff0c;算力结构发生改变。主动拥抱智算浪潮&#xff0c;持续输出优质算力支撑数字中国建设&#xff0c;适配泛在化、异构化算力推动…

JavaWeb之过滤器Filter(通俗易懂版)

今天开发遇到了&#xff0c;简单记录一下&#xff01; 简介&#xff1a;Filter是JavaWeb三大组件之一&#xff08;Servlet程序、Listener监听器、Filter过滤器&#xff09; 作用&#xff1a;既可以对请求进行拦截&#xff0c;也可以对响应进行处理。 1、Filter中的三个方法 …

【无标题】c++异常机制的一些总结以及思考

在谈及c处理异常机制的方法之前我们不妨来回顾一下c语言是如何应对这块的。 终止程序&#xff0c;如assert&#xff0c;缺陷&#xff1a;用户难以接受。如发生内存错误&#xff0c;除0错误时就会终止程序。 返回错误码&#xff0c;缺陷&#xff1a;需要程序员自己去查找对应的…

深兰科技再获欧洲订单,中国造智能机器人出海“服务”西班牙

近日&#xff0c;经过包含关键技术、场景适配性、任务完成效率、产品操作便捷度等考核标准在内多轮综合对比&#xff0c;深兰科技突出重围&#xff0c;斩获西班牙一笔价值百万的智能室内清洁机器人采购订单。 多重问题显示&#xff0c;欧洲清洁市场亟待科技赋能 在当前的经济形…

VUE初级知识点总结

前言 近几年随着HTML5的普及&#xff0c;原来的jsp逐渐在被淘汰&#xff0c;而vue成了很多前端开发者的心仪的js框架&#xff0c;因为它相对于其他两大框架&#xff08;Angula、React&#xff09;更简单易学&#xff0c;当然了这里的简单易学指的是上手快&#xff0c;在不知道…

7.3 股票分析(project)

目录 第1关&#xff1a;涨幅和成交量 第2关 涨幅与最高价 第3关 跌幅与最低价 本关任务&#xff1a;完成涨幅和成交量股票分析。 相关知识 1.sorted()函数 2.集合运算 sorted()函数 sorted() 函数对所有可迭代的对象进行排序操作。 sorted(iterable, keyNone, reverseFal…

Linxu下性能指标采集工具之nmon工具的使用

前言 近期在测试JefLogTail&#xff0c;由于JefLogTail使用的是轮询的方式来监听文件夹&#xff0c;所以对cpu的消耗可能会高一些&#xff0c;所以在测试的时候着重关注CPU,Linux下查看CPU信息一般采用top命令来实时观察&#xff0c;但是这种对于只是通过观察数据的变化来评估…

跟着我学习 AI丨初识 AI

人工智能&#xff08;AI&#xff09;是一种模拟人类思维和行为的计算机技术&#xff0c;通过学习、推理和自我修正等方式&#xff0c;使机器能够模拟人类智能&#xff0c;并具有一定的自主决策能力。AI 可以被用于解决各种难题&#xff0c;如自动化、机器人、自动驾驶、语音识别…

【LeetCode】53. 最大子数组和

53. 最大子数组和&#xff08;中等&#xff09; 思路 这道题的状态设计和状态转移和 300. 最长递增子序列 类似。但是这里要求的是连续子数组&#xff0c;和子序列不同。 状态定义 首先定义 dp[i]&#xff1a;以 nums[i] 结尾的具有最大和的连续子数组。 状态转移方程 根据…

idea项目打成war包,出现路径问题(已解决)

参考文档&#xff1a; https://www.cnblogs.com/huaixiaonian/p/10521460.html 解释说明&#xff1a; 什么路径问题呢&#xff0c;就比如你们合作开发了一个项目&#xff0c;然后打成了一个war包&#xff0c;然后路径以前的是这种的 http://localhost:8080 就可以直接运行&…