数据结构(特殊二叉树-平衡二叉树)

平衡二叉树(AVL树)

  • 前提一定是搜索二叉树,对于根节点的左右子树的高度差不能超过1,并且所有子树都要循序这个要求

  • 如果一个搜索二叉树呈现或接近单支状,它的查找效率很低,很接近链表,因此如果能让它平衡时,查找效率最高

  • 由于节点的位置要受到相互之间值的影响,并且在往平衡二叉树中添加节点或者删除节点前,二叉树本身是平衡的,所以只可能在最后操作的节点附近不满足平衡条件,因此需要在该过程中对该节点进行判断并调整。

  • 因此一棵平衡二叉树因为添加操作导致不平衡的原因,总结就四种:

第一种:x                               y/   \                          /     \    y    t1                        z       x/   \                          /   \   /   \z    t2                        t3  t4   t2  t1/ \t3 t4              以y为轴 右旋转第二种:x                             y/   \                         /   \t1    y                       x     z/   \                    / \   / \t2    z                  t1 t2 t3 t4/ \t3  t4  以y为轴 左旋转第三种:x               x                z/   \            / \             /   \y    t1          z  t1           y     x /   \             / \            /  \   /  \t2    z           y  t4          t2  t3 t4  t1   / \         / \ t3 t4       t2 t3    先以z为轴左旋转          再以z为轴右旋转 达到平衡第四种:x               x                z/   \            / \             /   \t1    y          t1  z           x     y /   \           / \         /  \  /  \z    t2         t3  y       t1  t3 t4 t2   / \                 / \ t3 t4               t4 t2    先以z为轴右旋转          再以z为轴左旋转 达到平衡
删除节点
  • 待删除的节点是叶子节点,直接删除

  • 待删除节点的左子树或者右子树为空,则使用非空节点替换

  • 待删除节点左右子树非空,则根据左右子树的高度,选择高的一边子树,如果是左子树高,选择左子树中的最大节点赋值给待删除节点,然后再左子树中继续删除该最大节点,相当于继续处理情况1或情况2;如果是右子树高,则在右子树选择最小值节点继续同样处理。

  • 删除后可能导致不平衡,需要重新调整平衡

平衡二叉树的优点:

避免了二叉搜索树呈现单支状,让其能以最佳的效率进行查找操作 O(log2n)

平衡二叉树的缺点:

在插入、删除操作时,为了达到平衡需要进行大量的左旋、右旋操作、计算高度,所以此时操作速度慢

因此AVL树适合在数据量大并且数据量比较稳定,没有太多的插入、删除操作,适合大量的查找操作。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>//	设计二叉树节点结构
typedef struct TreeNode
{int data;struct TreeNode* left;struct TreeNode* right;
}TreeNode;//	创建节点
TreeNode* create_tree_node(int data)
{TreeNode* node = malloc(sizeof(TreeNode));node->data = data;node->left = NULL;node->right = NULL;return node;
}//	求高度
int high_tree(TreeNode* root)
{if(NULL == root) return 0;int lh = high_tree(root->left);int rh = high_tree(root->right);return lh>rh ? lh+1 : rh+1;
}//	计算左右子树高度差
int def_high(TreeNode* root)
{if(NULL == root) return 0;return high_tree(root->left) - high_tree(root->right);
}//	左旋转
TreeNode* left_rotate(TreeNode* x)
{TreeNode* y = x->right;TreeNode* t2 = y->left;y->left = x;x->right = t2;return y;
}//	右旋转
TreeNode* right_rotate(TreeNode* x)
{TreeNode* y = x->left;TreeNode* t2 = y->right;y->right = x;x->left = t2;return y;
}//	自动调整平衡 并返回调整后的根节点
TreeNode* auto_balance(TreeNode* x)
{if(NULL == x) return NULL;int lh = high_tree(x->left);int rh = high_tree(x->right);//	左子树高于右子树 超过1if(lh - rh > 1){//	情况1if(def_high(x->left) >= 0){//	右旋转x = right_rotate(x);}//	情况3else {//	左旋转x->left = left_rotate(x->left);//	右旋转x = right_rotate(x);}}//	或者 右高于左 超过1else if(rh - lh > 1){//	情况2if(def_high(x->right) <= 0){//	左旋转x = left_rotate(x);}//	情况4else{//	右旋转x->right = right_rotate(x->right);//	左旋转x = left_rotate(x);}}return x;
}//	添加 返回添加成功后的根节点
TreeNode* insert_tree(TreeNode* root,int data)
{if(NULL == root)return create_tree_node(data);//	节点添加到合适的位置中if(data < root->data)root->left = insert_tree(root->left,data);elseroot->right = insert_tree(root->right,data);//	有可能添加后该位置破坏平衡 需要调整root = auto_balance(root);return root;
}//	找最大值
TreeNode* max_tree_node(TreeNode* root)
{if(NULL == root) return NULL;TreeNode* max = root;while(max->right) max = max->right;return max;
}//	找最小值
TreeNode* min_tree_node(TreeNode* root)
{if(NULL == root) return NULL;TreeNode* min = root;while(min->left) min = min->left;return min;
}TreeNode* delete_tree(TreeNode* root,int data)
{if(NULL == root) return NULL;if(root->data == data){//	左右皆空 直接删if(NULL == root->left && NULL == root->right){free(root);return NULL;}//	左空 替换为右子树 if(NULL == root->left){TreeNode* temp = root->right;free(root);return temp;}//	右空 替换为左子树if(NULL == root->right){TreeNode* temp = root->left;free(root);return temp;}//	左右都非空//	左边高if(def_high(root) >= 0){TreeNode* max = max_tree_node(root->left);root->data = max->data;root->left = delete_tree(root->left,max->data);}//	右边高else{TreeNode* min = min_tree_node(root->right);root->data = min->data;root->right = delete_tree(root->right,min->data);}//	重新调整平衡root = auto_balance(root);return root;}if(data < root->data)root->left = delete_tree(root->left,data);else root->right = delete_tree(root->right,data);//	重新调整平衡root = auto_balance(root);return root;
}//	遍历
void dlr_show(TreeNode* root)
{if(NULL == root) return;printf("%d ",root->data);dlr_show(root->left);dlr_show(root->right);
}void ldr_show(TreeNode* root)
{if(NULL == root) return;ldr_show(root->left);printf("%d ",root->data);ldr_show(root->right);
}void lrd_show(TreeNode* root)
{if(NULL == root) return;lrd_show(root->left);lrd_show(root->right);printf("%d ",root->data);
}int main(int argc,const char* argv[])
{TreeNode* root = NULL;for(int i=0; i<10; i++){root = insert_tree(root,i+1);}root = insert_tree(root,20);root = delete_tree(root,4);dlr_show(root);printf("\n");ldr_show(root);printf("\n");lrd_show(root);printf("\n");
}

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

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

相关文章

回望林徽因,给心怀梦想的女孩子以精神的力量。|于女生,影响你的命运的一个很重要的因素是将来的伴侣。

文章目录 引言I 《回望林徽因,给心怀梦想的女孩子以精神的力量。》怎样活出生命的价值和精彩?相爱的两个人,需要注意的地方是?普通日子的浪漫,藏在哪些细节里?一个女性最有魅力的时刻是?写作的美妙之处是什么?为什么说笑起来的样子很美?自由辽阔的心境,是什么样的感觉…

python中的fire和Linux shell中的参数传递

一、fire 安装 要使用 Python Fire 库&#xff0c;首先需要安装它。以下是安装步骤&#xff1a; 使用 pip 安装 可以通过 pip 直接安装 Python Fire&#xff1a; pip install fire 特性 自动生成命令行界面&#xff1a;将任何 Python 对象&#xff08;函数、类、模块、字…

nodejs编译报错 集合

目录 一、使用命令编译typescript时报错&#xff0c;报错文件tsconfig.json 二、npm start运行后报错&#xff0c;could not find module 一、使用命令编译typescript时报错&#xff0c;报错文件tsconfig.json npx tsc 报错&#xff1a; Specified include paths were [&…

秋招突击——7/24——知识补充——JVM类加载机制

文章目录 引言类加载机制知识点复习类的生命周期1、加载2、连接——验证3、连接——准备4、连接——解析5、初始化 类加载器和类加载机制类加载器类加载机制——双亲委派模型 面试题整理1、类加载是什么2、类加载的过程是什么3、有哪些类加载器&#xff1f;4、双亲委派模型是什…

Redis一致性与分布式锁

Redis一致性 何为redis一致性 即在项目中&#xff0c;redis缓存中的数据要与数据库当中的数据保持一致。 那么这里&#xff0c;就会有小伙伴要问了&#xff0c;redis缓存中的数据不就是从数据库当中查询出来的吗&#xff1f;怎么会不一致呢&#xff1f; 笔者在这里解答一下…

Unite 上海 强势回归

​​​ 他回归了 Unite 大会是一年一度的 Unity 全球开发者盛会。今年&#xff0c;Unite 将于 7 月盛夏点亮上海外滩。此次盛会&#xff0c;我们将以“团结”为核心&#xff0c;凝聚全球 3000 多位 Unity 社区精英的力量&#xff0c;共同开启 Unity 技术的新纪元。 在这里&am…

UE学习笔记--干货满满!FString 的 Equals 和 == 源码深度探析

目录 前言FString 的 operatorESearchCaseStricmpBothAsciiLowerAsciiStricmp 结论Stricmp 代码验证整理思路 前言 最近大概写了如下代码 TArray<FString> TestArray; FString Z1 "Z1", z1 "z1"; TestArray.Emplace(Z1);if(TestArray.Contains(z…

代码随想录第十七天|动态规划(1)

目录 LeetCode 509. 斐波那契数列 LeetCode 70. 爬楼梯 LeetCode 746. 使用最小花费爬楼梯 LeetCode 62. 不同路径 LeetCode 63. 不同路径 II 总结 动态规划在算法课上学习过&#xff0c;看过了之后有一些熟悉感。&#xff08;虽然贪心算法也学过&#xff0c;但是不如动态…

样式迁移及代码

一、定义 1、使用卷积神经网络&#xff0c;自动将一个图像中的风格应用在另一图像之上&#xff0c;即风格迁移&#xff1b;两张输入图像&#xff1a;一张是内容图像&#xff0c;另一张是风格图像。 2、训练一些样本使得样本在一些cnn的特征上跟样式图片很相近&#xff0c;在一…

Java字符串与Unicode编码(码点、代码单元、基本多语言平面BMP、辅助平面、代理对)

Java字符串与Unicode编码 1. Unicode编码简介 Unicode是一个为世界上所有书写系统设计的字符编码标准。它旨在解决不同编码标准之间不兼容的问题&#xff0c;使得计算机能够处理和显示世界上几乎所有的字符。Unicode为每个字符分配了一个唯一的数字&#xff0c;称为“码点”&…

字典集合案例

1.统计字符 统计字符串中每个字符出现的次数 s l like summer very much #去掉空格 s s.replace(" ","") d dict() for i in s:if i in d:d[i] 1else:d[i] 1 for i in d:print(i,d[i]) 2.求不重复的随机数 #导入随机数 import random a int(input(&q…

自动化测试的艺术:Xcode中GUI测试的全面指南

自动化测试的艺术&#xff1a;Xcode中GUI测试的全面指南 在软件开发过程中&#xff0c;图形用户界面&#xff08;GUI&#xff09;测试是确保应用质量和用户体验的关键环节。Xcode&#xff0c;作为苹果的官方集成开发环境&#xff08;IDE&#xff09;&#xff0c;提供了一套强大…

智能疲劳驾驶检测:基于YOLO和深度学习的全流程实现

引言 疲劳驾驶是导致交通事故的重要原因之一。为了提高道路安全&#xff0c;及时检测和预警驾驶员的疲劳状态显得尤为重要。本文介绍了一种基于深度学习的疲劳驾驶检测系统。该系统利用YOLO模型&#xff08;YOLOv8/v7/v6/v5&#xff09;进行疲劳驾驶检测&#xff0c;并提供了详…

OD C卷 - 密码输入检测

密码输入检测 &#xff08;100&#xff09; 给定一个密码&#xff0c;‘<’ 表示删除前一个字符&#xff0c;输出最终得到的密码&#xff0c;并判断是否满足密码安全要求&#xff1a; 密码长度>8;至少包含一个大写字母&#xff1b;至少包含一个小写字母&#xff1b;至少…

探索若依(Ruoyi):开源的企业级后台管理系统解决方案

探索若依&#xff08;Ruoyi&#xff09;&#xff1a;开源的企业级后台管理系统解决方案 在现代企业管理中&#xff0c;拥有一个高效、稳定的后台管理系统是至关重要的。若依&#xff08;Ruoyi&#xff09;作为一款开源的企业级后台管理系统&#xff0c;为企业提供了丰富的功能…

SpringBoot中JSR303校验

JSR是 Java EE 的一种标准&#xff0c;用于基于注解的对象数据验证。在Spring Boot应用中&#xff0c;你可以通过添加注解直接在POJO类中声明验证规则。这样可以确保在使用这些对象进行操作之前&#xff0c;它们满足业务规则。个人认为非常有用的&#xff0c;因为它减少了代码中…

2.6基本算法之动态规划2989:糖果

描述 由于在维护世界和平的事务中做出巨大贡献&#xff0c;Dzx被赠予糖果公司2010年5月23日当天无限量糖果免费优惠券。在这一天&#xff0c;Dzx可以从糖果公司的N件产品中任意选择若干件带回家享用。糖果公司的N件产品每件都包含数量不同的糖果。Dzx希望他选择的产品包含的糖…

被问到MQ消息已丢失,该如何处理?

在分布式系统中&#xff0c;消息中间件&#xff08;如 RabbitMQ、RocketMQ、Kafka、Pulsar 等&#xff09;扮演着关键角色&#xff0c;用于解耦生产者和消费者&#xff0c;并确保数据传输的可靠性和顺序性。尽管我们通常会采取多种措施来防止消息丢失&#xff0c;如消息持久化、…

【Vue实战教程】之 Vue Router 路由详解

Vue Router路由 1 路由基础 1.1 什么是路由 用Vue.js创建的项目是单页面应用&#xff0c;如果想要在项目中模拟出来类似于页面跳转的效果&#xff0c;就要使用路由。其实&#xff0c;我们不能只从字面的意思来理解路由&#xff0c;从字面上来看&#xff0c;很容易把路由联想…

HTML(五)——HTML区块,布局

HTML区块 HTML可以通过 <div> 和 <span>将元素组合起来&#xff0c;可以来布局&#xff0c;就是盒子&#xff0c;div是块级盒子&#xff0c;里面 可以放任何东西&#xff0c;span里面装的是文本 HTML 区块元素 大多数 HTML 元素被定义为块级元素或内联元素。 实…