平衡二叉查找树

平衡二叉查找树的严格定义:二叉树中任意一个节点的左右子树的高度相差不能大于1。

设计平衡二叉查找树的初衷:为了解决普通二叉查找树在频繁的插入、删除等动态更新的情况下(尤其是插入的一组数据是有序的情况),出现时间复杂度退化的问题。

但是在实际的开发中,并不能完全严格的按照定义去做,只要保证平衡即可,也就是让整棵树左右看起来比较对称、比较平衡、更新数据时不要造成一边很高、一边又很低的情况。这样就能让整棵树的高度相对来说低一些(如树的高度是对数量级的,不必log2n大很多)。只要能保证这样,就可以说它是一个合格的平衡二叉查找树。

平衡二叉查找树-红黑树(R-B Tree)

红黑树中的节点,一类被标记为黑色,一类被标记为红色。并且要求:

    1. 每个节点不是黑色就是红色,根节点必须是黑色的(可以在节点数据结构中加一个数据字段代表颜色);
    1. 每个叶子节点都是黑色的空节点(nil)(为了保证除了根以外,每个节点都有兄弟节点,也就是每个父节点都有两个叉),也就是说叶子节点不存储数据;
    1. 任何相邻(线连着)的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的;
    1. 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点(说明黑色节点是要成对出现的,否则失去平衡了)。
为什么说红黑树是“近似平衡的”

近似平衡就是说查找等动态更新的性能不会退化太严重。

二叉查找树很多操作的性能都很树的高度成正比,因此只要证明红黑树的高度能比较稳定的趋近log2n就好。

去掉红色节点的黑色节点(无父节点则祖父节点代替,这样防止原本黑色节点的高度发生改变)可能变成3叉树/4叉树。他们要比相同节点数相同的完全二叉树的高度要小,所以它的高度不超过log2n。

而红色节点必须是被黑色节点隔开的,一红一黑,因此红色节点加回去,树的高度应该不大于2log2n。高度仅是大了一倍,性能上下降不多,可以近似O(logn)。

同时红黑树是近似平衡,因此维护平衡的成本较低,性能比较稳定。对于工程应用来说,要面对各种异常情况,稳定性很重要,因此红黑树的应用范围较广。

动态数据结构

动态数据结构是指支持动态的更新操作,里面存储的数据是时刻在变化的,它支持查询、删除、插入等操作,并且这些操作是非常高效。这样的数据结构才能算作动态数据结构。

如何维护红黑树的近似平衡

红黑树规定插入的节点必须是红色的且在修改过程中不能改变颜色,因为插入红色节点比黑色节点违背规则的可能性更小。插入黑色节点一定会改变黑色高度(违背规则4),而插入红色只有一半机会违背规则3。且3比4更易修正。

当插入一个新节点(二叉查找树插入新节点会插到叶子节点上,那么在红黑树上也就是插入到黑色空节点上层了)就可能会破坏红黑树原本结构,打破平衡,那么如何修正呢?

主要有三种方式:改变节点颜色、左旋、右旋。

  1. 变色 假设原本只有节点E,然后插入了节点A和S,再插入F:

  2. 左旋 通常左旋操作用于将一个向右倾斜的红色链接转为向左链接。

    动图效果:

  3. 左旋

动图效果:

红黑树的操作

  1. 节点数据
typedef struct TreeNode {int key;struct TreeNode *left;struct TreeNode *right;struct TreeNode *father; // 双向链表BOOL color;} Node;
复制代码
  1. 左旋的实现

/** 左旋示意图:对节点x进行左旋*     p                       p*    /                       /*   x                       y*  / \                     / \* lx  y      ----->       x  ry*    / \                 / \*   ly ry               lx ly* 左旋做了三件事:* 1. 将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时)* 2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右)* 3. 将y的左子节点设为x,将x的父节点设为y*/
复制代码
  1. 右旋的实现
/** 左旋示意图:对节点y进行右旋*        p                   p*       /                   /*      y                   x*     / \                 / \*    x  ry   ----->      lx  y*   / \                     / \* lx  rx                   rx ry* 右旋做了三件事:* 1. 将x的右子节点赋给y的左子节点,并将y赋给x右子节点的父节点(x右子节点非空时)* 2. 将y的父节点p(非空时)赋给x的父节点,同时更新p的子节点为x(左或右)* 3. 将x的右子节点设为y,将y的父节点设为x*/
复制代码
  1. 插入操作
  • 如果第一次插入,原本树是空的,则只需要将它涂黑即可。
  • 如果最终插入后,插入节点的父节点是黑色的,则不违反红黑树规则,不需改变。
  • 如果最终插入后,插入节点的父节点是红色的,就违反规则了,需要修改保持树的平衡了。此时又有三种情况:
    • ①插入节点的父节点和其叔叔节点(祖父节点的另一个子节点)均为红色的;
    • ②插入节点的父节点是红色,叔叔节点是黑色,且插入节点是其父节点的右子节点;
    • ③插入节点的父节点是红色,叔叔节点是黑色,且插入节点是其父节点的左子节点。

具体过程为例: 插入新节点4,如图1(也就是情况①)。此时违反3,因此将它的父节点涂黑,但是如果只涂5,就会造成黑色节点不平衡了,违反了4。因此新节点的父节点5和叔叔节点8都要涂黑。这时758都是黑色(黑色太多了?)将祖父7涂红。这时又变成情况②,把7当做新节点 ,以新节点 为支点做左旋操作。如图2->3。此时27节点仍有问题继续修改,此时那2作为新节点,将父节点7涂黑,祖父节点11涂红。在以11为支点右旋。这样整棵树就又平衡。

从上面的步骤可以看出,如果插入数据最终是情况1,则需要走完2、3步骤;如果插入数据出现的是情况2,则只需走完3;插入后是3,则完成3即可了。

总体:变色->左旋->右旋

资料

转载于:https://juejin.im/post/5c0897dae51d45430f07a08d

数据结构与算法-学习笔记(18)相关推荐

  1. 数据结构与算法学习笔记——链栈

    数据结构与算法学习笔记(C语言) 链栈 在开始链栈的学习之前,我们先实现一下上一篇文章中提到的检查括号匹配的小程序,鉴于水平有限,本人就随便写一下代码好了,目标仅限于对功能的实现. /*用顺序栈这种数 ...

  2. 数据结构与算法 学习笔记(5):字符串

    数据结构与算法 学习笔记(5)- 字符串 本次笔记记录了LeetCode中关于字符串的一些问题,并给出了相应的思路说明和代码.题目编号与LeetCode对应,方便查找. 题目1:LeetCode 13 ...

  3. 数据结构与算法学习笔记之 从0编号的数组

    数据结构与算法学习笔记之 从0编号的数组 前言 数组看似简单,但掌握精髓的却没有多少:他既是编程语言中的数据类型,又是最基础的数据结构: 一个小问题: 为什么数据要从0开始编号,而不是 从1开始呢? ...

  4. 数据结构与算法学习笔记之 提高读取性能的链表(上)

    数据结构与算法学习笔记之 提高读取性能的链表(上) 前言 链表(Linked list)比数组稍微复杂一点,在我们生活中用到最常见的应该是缓存,它是一种提高数据读取性能的技术,常见的如cpu缓存,浏览 ...

  5. 数据结构与算法学习笔记4:递归+分治法

    数据结构与算法学习笔记4 递归 斐波那契数列 青蛙跳台阶问题 链表倒序打印 分治法 二分查找/折半查找 Binary Search 题目1:快速幂 题目2:如何判断一个数是否为2的次幂 递归 指在函数 ...

  6. 数据结构与算法学习笔记15:最大流问题 / 二分图 / 有权无权二分图的匹配 / 匈牙利算法 / 银行家算法 / 稳定婚配

    数据结构与算法学习笔记15:最大流问题 / 二分图 / 有权无权二分图的匹配 / 匈牙利算法 / 银行家算法 / 稳定婚配 引入小题:最短路径 最大流问题(maximum flow problem) ...

  7. 数据结构与算法学习笔记——图 C++实现

    数据结构与算法学习笔记--图 C++实现 1 概念 2 图的表示方法 3 算法 3.1 拓扑排序 3.2 图的搜索算法 3.2.1 广度优先搜索(BFS) 3.2.2 深度优先搜索(DFS) 3.3 ...

  8. 数据结构与算法学习笔记之先进先出的队列

    前言 队列是一种非常实用的数据结构,类似于生活中发排队,可应用于生活,开发中各个方面,比如共享打印机(先请求先打印),消息队列.你想知道他们是怎么工作的么.那就来一起学习一下队列吧 正文 一.队列的定 ...

  9. 数据结构与算法 学习笔记(8):字典、集合、哈希表

    数据结构与算法 学习笔记(8):字典.集合.哈希表 本次文章记录的是和字典.集合.哈希表等数据结构相关的LeetCode算法题(题号与LeetCode对应),包括其构造和使用,针对每一题或一类题给出了 ...

  10. 【数据结构与算法学习笔记】

    文章目录 前言 0 Preview与算法复杂度分析简述 1 线性数据结构 1.1 Stack 1.2 Queue 1.3 Deque 1.4 UnorderedList 1.5 OrderedList ...

最新文章

  1. 新手入门:Kaggle NLP比赛总结
  2. main函数第3个参数envp装的是什么(envp:环境变量)
  3. 可视化COCO分割标注文件,以及单个json合成coco格式标注文件
  4. 【刷出存在感】锋会圆桌现场
  5. 软件工程结构化建模的方法和工具_软件工程导论知识点梳理之概念题
  6. 黑客专用Linux发行版Kali Linux发布滚动更新版2016.1
  7. 修改小程序radio组件的默认样式
  8. 二级c语言上机程序填空,浙江省计算机二级c语言上机考试真题(二)程序填空
  9. http请求消息体和响应消息体
  10. Exchange Server 2010高可用性配置
  11. 决策树(八)--随机森林及OpenCV源码分析
  12. 【Python】python帮助文档
  13. Spring MVC学习(6)—Spring数据类型转换机制全解【一万字】
  14. 计算机二级主要是学什么,计算机二级ms office考的都是什么内容
  15. Mac使用系列之软件安装权限
  16. 数字电视业务PSI/SI学习系列
  17. 一行代码完成Java的Excel读写 侵立删
  18. unity种四种光源
  19. 华为IoT首席架构师王启军:全栈工程师“养成记”
  20. ios开发之公交卡系统的设计与实现

热门文章

  1. vscode中如何拉取git代码_工具 | 手把手教你在VSCode中使用Git
  2. Name or service not know
  3. Windows 增加 Open command window here 选项
  4. php百度地图地址解析失败,javascript - vue中使用百度地图 提示无法解析
  5. 借一本可以编辑HTML,index.html
  6. python输出99乘法表_如何用python输出99乘法表
  7. oa中获取当前用户信息
  8. 关于问题PageNotFound.noHandlerFound No mapping found for HTTP的解决
  9. 分享三个USB抓包软件---Bus Hound,USBlyzer 和-USBTrace
  10. 一个API方式存取日志文件的模块[VB]