文章目录

  • 前言
  • 一.定义
  • 二.基本操作
    • 1.查找,
    • 2.插入(如何调整)
      • 如何调整
      • 代码实现插入

前言

首先我们来思考一下一个普通二叉树保存数据,如果想查找一个数据,由于普通二叉树保存数据是随机的,要找到数据的时间复杂度为O(n)。后面为了方便
,我们又学习二叉搜索树,它的定义是将比根节点小的数放左边,比根节点大的数放右边,并且每一课子树都是二叉搜索树这样使得数据在树上存储有一定
的规律,在一定情况下查找起来很方便。但是,二叉搜索数当给出数据的顺序不同时,二叉搜索树也会不同。比如如果给出的序列为{1,2,3,4,5}或
{3,2,1,4,5}两颗二叉搜索树会截然不同,查找效率也会不同。
我们知道一颗树的查找效率与树的高度有关,最好的树结构当然是满二叉树或者是完全二叉树,我们称这种树是平衡的。由我们知道二叉搜索树在一定情况下可以达到很好的查找效率。但是,通常情况二叉搜索树的结点插入顺序并不能事先确定,动态查找(查找时同时进行删除与插入操作)的时候总还是会改变数的结构,不能做到平衡。所以,我们就需要考虑如何保证既能完成动态查找,又能保持一个较完美树结构的二叉搜索树。这样我们就有两个问题需要考虑:一个是标准,什么样的树才是一颗树结构好的树,第二是平衡化处理,怎样使其达到平衡。

一.定义

平衡二叉树又称AVL树(由发明它的两位数学家名字命名),它仍然是一颗二叉搜索树,所以具备二叉搜索树的所有性质,只是加上了"平衡"的限制。
平衡二叉树要不是一颗空树,要不是具备以下条件的非空二叉搜索树:
1. 左右子树高度差的绝对值不能超过1(平衡因子,相当于一种标准)。
2. 左右子树仍然是一颗平衡二叉树。
有了平衡因子的定义,我们就可以找出不平衡的树,然后再对其进行平衡化处理,处理的具体内容分如下。处理完后使树的高度能保持在O(logn)级别,使得
查找操作的时间复杂度为O(logn).


图1图2圆上为平衡因子的值,明显图1不是平衡二叉树,有提个点的平衡因子超过了1。图2是平衡二叉树。

二.基本操作

1.查找,

由于平衡二叉树仍是一颗二叉搜索树,其查找操作并不会改变平衡因子,所以与二叉搜索树的操作相同。可见博客:二叉搜索树的查找。

2.插入(如何调整)

如何调整

假设这里有一颗平衡二叉树:(上方代表平衡因子)

LL型
当要往D的左子树或者右子树插入结点时,此时破坏了原来平衡二叉树的平衡结构,如图:此时A结点的平衡因子超过了1,我们称A结点为发现问题结点,六角星为产生问题结点。

此时,我们需要看发现问题结点与产生问题结点路径上,从发现问题结点开始的连续三个结点。入上图的A->B->D。我们发现这三个结点都在发现问题结点A左子树的左子树上,我们称这种不平衡状态为LL型(向左倾斜)不平衡。
如何调整,LL型不平衡的调整策略主要将这三个结点(A,B,D)顺时针旋转,并且仍然要是一颗二叉搜索树。
由于二叉搜索树的性质:

  1. 将B结点的右子树成为A的左子树。(B的左子树比B大,比A小)
  2. 让A成为B的右子树(A比B大)
  3. 将根节点设为B

    显然只有只有从根节点到插入结点路径上的结点才会发生平衡因子的变化,因此只需要对这条路径上的失衡的结点进行调整,并且只需要把最靠近插入节点的失衡节点调整到正常,路径上的所有结点都会平衡。所以发现问题的结点不一定是根节点
    注意:看的是发现问题结点到产生问题结点路径上,从发现问题结点开始的连续三个结点的方向,确定是什么型。并且主要也是调整这三个结点。
    代码如下:
void SigelleftCir(Bactree **tree){//LL旋转Bactree *temp = NULL;temp = (*tree)->left;(*tree)->left = temp->right;temp->right = (*tree);(*tree)->hight = (GetHight((*tree)->left) > GetHight((*tree)->right) ? GetHight((*tree)->left) : GetHight((*tree)->right)) + 1;//调整后要保持每个结点高度正确。temp->hight = (GetHight(temp->left) > GetHight(temp->right) ? GetHight(temp->left) : GetHight(temp->right)) + 1;(*tree) = temp; //要赋值给(*tree),不然temp才是正确的树}

RR型
RR型的处理方法与LL型类似,如图:


产生问题结点为六角星结点(插入E的左子树或者右子树),发现问题结点为A结点。路径上从发现问题结点开始的连续三个结点为(A,C,E)结点,分别在发现问题结点右子树的右子树上,所以为RR型(向右倾斜)不平衡。
调整方式:主要将这三个结点(A,C,E)逆时针旋转,并且仍然要是一颗二叉搜索树。

  1. 将C结点的左子树成为A的右子树。
  2. 让A成为C的左子树
  3. 将根节点设为C
void SigelrightCir(Bactree **tree){//RR旋转,与LL一样Bactree *temp = NULL;temp = (*tree)->right;(*tree)->right = temp->left;temp->left = (*tree);(*tree)->hight = (GetHight((*tree)->left) > GetHight((*tree)->right) ? GetHight((*tree)->left) : GetHight((*tree)->right)) + 1;temp->hight = (GetHight(temp->left) > GetHight(temp->right) ? GetHight(temp->left) : GetHight(temp->right)) + 1;(*tree) = temp;

LR型

产生问题结点为六角星(插入E的左子树或者右子树),发现问题结点为A结点。路径上从发现问题结点开始的连续三个结点为(A,B,E)结点,分别在发现问题结点左子树的右子树上,所以为LR型不平衡。
调整方式:“左-右双旋”,主要先将B结点作为根节点逆时针旋转(左旋),再以A结点作为根节点顺时针旋转(右旋)。(画图以白色六角星作为插入)

代码实现调整LR型就很简单了,先右旋,再左旋

void LeftrightCir(Bactree **tree){//LR旋转SigelrightCir(&((*tree)->left));SigelleftCir(tree);
}

RL型

产生问题结点为六角星(插入D的左子树或者右子树),发现问题结点为A结点。路径上从发现问题结点开始的连续三个结点为(A,C,D)结点,分别在发现问题结点右子树的左子树上,所以为RL型不平衡。
调整方式:"右-左双旋"主要先将C结点作为根节点顺时针旋转(右旋),再以A结点作为根节点逆时针旋转(左旋)。(画图以白色六角星作为插入)

代码实现调整RL型就很简单了,先左旋,再右旋

void RightleftCir(Bactree **tree){//RL旋转SigelleftCir(&((*tree)->right));SigelrightCir(tree);
}

代码实现插入

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#pragma warning(disable:4996)typedef int Elementtype;
typedef struct Balacetree{//二叉树信息Elementtype val;int hight;struct Balacetree *left;struct Balacetree *right;}Bactree;Bactree *TreeNodeCreate(Elementtype x){//创建树节点Bactree *tree = (Bactree *)malloc(sizeof(Bactree));tree->val = x;tree->hight = 1;tree->left = NULL;tree->right = NULL;return tree;
}int GetHight(Bactree *tree){//求树高度if (!tree){return 0;}int H;int LH;int RH;LH = GetHight(tree->left);RH = GetHight(tree->right);H = LH > RH ? LH : RH;return H + 1;
}
void SigelleftCir(Bactree **tree){//LL旋转Bactree *temp = NULL;temp = (*tree)->left;(*tree)->left = temp->right;temp->right = (*tree);(*tree)->hight = (GetHight((*tree)->left) > GetHight((*tree)->right) ? GetHight((*tree)->left) : GetHight((*tree)->right)) + 1;//调整后要保持每个结点高度正确。temp->hight = (GetHight(temp->left) > GetHight(temp->right) ? GetHight(temp->left) : GetHight(temp->right)) + 1;(*tree) = temp; //要赋值给(*tree),不然temp才是正确的数}
void SigelrightCir(Bactree **tree){//RR旋转,与LL一样Bactree *temp = NULL;temp = (*tree)->right;(*tree)->right = temp->left;temp->left = (*tree);(*tree)->hight = (GetHight((*tree)->left) > GetHight((*tree)->right) ? GetHight((*tree)->left) : GetHight((*tree)->right)) + 1;temp->hight = (GetHight(temp->left) > GetHight(temp->right) ? GetHight(temp->left) : GetHight(temp->right)) + 1;(*tree) = temp;}void LeftrightCir(Bactree **tree){//LR旋转SigelrightCir(&((*tree)->left));SigelleftCir(tree);
}
void RightleftCir(Bactree **tree){//RL旋转SigelleftCir(&((*tree)->right));SigelrightCir(tree);
}Bactree *BalaceTreePush(Bactree **tree, Elementtype x){if (!(*tree)){     //插入结点*tree=TreeNodeCreate(x);return *tree;}if ((*tree)->val > x){  //x小的插入左边(*tree)->left = BalaceTreePush(&((*tree)->left), x);//往右边找,将结点返回给左指针//为什么放循环里,放循环里确认了一个方向,是左边if (GetHight((*tree)->left) - GetHight((*tree)->right) >= 2){//平衡因子if ((*tree)->left->val > x){//确认了第二个方向 左边SigelleftCir(tree);//LL}else{//右边LeftrightCir(tree);//LR}}}else{(*tree)->right = BalaceTreePush(&((*tree)->right), x);if (GetHight((*tree)->left) - GetHight((*tree)->right) <= -2){//注意是-2if ((*tree)->right->val < x){SigelrightCir(tree);}else{RightleftCir(tree);}}}(*tree)->hight = (GetHight((*tree)->left) > GetHight((*tree)->right) ? GetHight((*tree)->left) : GetHight((*tree)->right)) + 1;//更新高度return *tree;}void Print(Bactree *tree){if (tree){Print(tree->left);printf("%d ", tree->val);Print(tree->right);}
}int main(){Bactree *T = NULL;BalaceTreePush(&T, -10);BalaceTreePush(&T, -3);BalaceTreePush(&T, 0);BalaceTreePush(&T, 5);BalaceTreePush(&T, 9);BalaceTreePush(&T, 10);Print(T);system("pause");return 0;
}

数据结构——平衡二叉树(AVL树)之插入相关推荐

  1. Java数据结构——平衡二叉树(AVL树)

    AVL树的引入 搜索二叉树有着极高的搜索效率,但是搜索二叉树会出现以下极端情况: 这样的二叉树搜索效率甚至比链表还低.在搜索二叉树基础上出现的平衡二叉树(AVL树)就解决了这样的问题.当平衡二叉树(A ...

  2. 数据结构-平衡二叉树(AVL树)

    目录 1,平衡二叉树的介绍 1.1,二叉排序树存在的问题 1.2,平衡二叉树 1.3,平衡二叉树的创建 1.4,平衡二叉树的查找 2,代码实现 2.1,平衡二叉树的节点类型 2.2,LL旋转(单右旋转 ...

  3. Python数据结构11:树的实现,树的应用,前中后序遍历,二叉查找树BST,平衡二叉树AVL树,哈夫曼树和哈夫曼编码

    1.概念 树一种基本的"非线性"数据结构. 相关术语: 节点Node:组成树的基本部分.每个节点具有名称,或"键值",节点还可以保存额外数据项,数据项根据不同的 ...

  4. java数据结构与算法之平衡二叉树(AVL树)的设计与实现中的事实代码

    普通二叉查找树的问题   在开篇,我们提到过,普通二叉树(二叉查找树)在操作的时间复杂度上不一定遵循O(㏒n),也有可能是O(n),这是为什么呢?在上一篇中,我们明明插入都按照一定规则比较的呀,其实那 ...

  5. 一种基于平衡二叉树(AVL树)插入、查找和删除的简易图书管理系统

    目录 1. 需求分析 2. 项目核心设计 2.1 结点插入 2.2 结点删除 3 测试结果 4 总结分析 4.1 调试过程中的问题是如何解决的,以及对设计与实现的回顾讨论和分析 4.2 算法的时间和空 ...

  6. 平衡二叉树,AVL树之图解篇

    学习过了二叉查找树,想必大家有遇到一个问题.例如,将一个数组{1,2,3,4}依次插入树的时候,形成了图1的情况.有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本.而只有建 ...

  7. c++《AVL树的概念》《AVL树的插入》《AVL树的旋转》《AVL树的验证》《AVL树的删除》《AVL树的性能》

    4.1 AVL树 4.1.1 AVL树的概念 二叉搜索树虽可以缩短查找的效率,**但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当 于在顺序表中搜索元素,效率低下.**因此,两位俄罗斯的 ...

  8. [ 数据结构 - C++] AVL树原理及实现

    问题引入: 在上文我们提到了二叉搜索树在按值顺序插入时,会形成单边树,会大大降低二叉搜索树的性能.因此我们要将二叉搜索树进行平衡,采取适当的平衡措施,从而减低二叉搜索树的高度,使二叉搜索树达到一个接近 ...

  9. AVL树的插入(C++实现)

    1. 概念 AVL树(Adelson-Velsky and Landis Tree)于1962年被提出,是计算机科学中最早被发明的平衡二叉查找树.AVL树得名于它的发明者G. M. Adelson-V ...

最新文章

  1. python输入函数后无法运行_python - 如何在函数运行期间忽略所有用户输入?_python_酷徒编程知识库...
  2. Web Service未定义的解决办法
  3. 在已有SQL 2005 Server 群集中添加节点
  4. golang插入字符串_golang 几种字符串的连接方式
  5. iOS开发之如何将字典转为模型
  6. 有没有比python更简单的语言排名_5月语言排行榜:R跌出前二十 Python紧咬C++
  7. A/D转换器(华中师范)
  8. Java成神之路——volatile是什么?
  9. 95-864-040-源码-HDFS-Flink 和 HDFS 的交互
  10. 封年大促|年货节优秀PSD分层模板
  11. mysql list转表_mysql系统表【转】
  12. Test from Windows Live Writer
  13. uartz Spring与Spring Task总结
  14. springboot输出日志到文件配置
  15. SAP PP制造生产教程
  16. java基于ssm三大框架的小区物业收费报修管理系统
  17. 浅显易懂——泰勒展开式
  18. Tesseract-OCR 4.0LSTM训练流程 (Windows环境下)
  19. 微信群舆情怎么监测?
  20. linux面试题_全网最新、最全Linux面试题(2020版)!

热门文章

  1. 玩家眼中的10大最烧钱网络游戏
  2. 高等数学——简单直观地了解定积分
  3. 软件生成问候图片_省时省力,独一无二的素材一键生成!这些设计神器玩上瘾!|艺范分享...
  4. 速度精度双SOTA! TPAMI2022最新车道线检测算法(Ultra-Fast-Lane-Detection-V2)
  5. 易语言通达信交易api接口是什么?
  6. 沃尔玛申请了个物联网专利 能做到“补货”自动下单
  7. ios系统元素悬浮滑动错乱,和ios页面无故刷新问题
  8. php虚拟电话号码,[视频]一号通电信诈骗追踪 虚拟号码服务藏漏洞
  9. MySQL:复杂一点的查询----Datawhale第三次打卡笔记
  10. 数商云采购管理系统解决方案:助力企业采购平台数字化转型