二叉排序树、平衡二叉树、B树&B+树、红黑树的设计动机、缺陷与应用场景
之前面试时曾被问到“如果实现操作系统的线程调度应该采用什么数据结构?”,因为我看过ucore的源码,知道ucore是采用斜堆的方式实现的,可以做到O(n)的插入、O(1)的查找。我回答了斜堆,但面试官坚持让我在B树和红黑树之间选择一个,由于实际上很少用到B树和红黑树,所以我也不太清楚,只是隐约记得红黑树用于磁盘读取比较好,好像和数据大小和数据连续性相关,显然我记错了。当时觉得红黑树还有一些应用,应该命中的可能性比较大,就随意答了红黑树。当然回答错啦,面试官还给我简单讲解了一下,一直想着有机会好好总结一下这几个树的设计动机、缺陷和应用场景。最近有些时间,决定好好复习一下,毕竟数据结构才是基础。
树
为什么要引入树呢?一般在学习数据结构时,往往先学习向量和列表,然后是栈与队列。事实上,栈与队列只是在组织数据时额外加入了一些限制,分别是先进后出和先进先出,向量和列表都可以实现这种策略。那么向量和列表又存在什么缺陷呢?一般来讲,我们需要对数据结构做静态操作和动态操作,静态操作就是查找,动态操作就是插入和删除。在C/C++中一般采用数组实现向量,采用链表实现列表。接下来我们看一下它们的静态和动态操作的时间开销。
| 向量 | 列表
- | :-: | -:
静态操作(查找) | O(1)| O(n)
动态操作(插入、删除) | O(n) | O(1)
可以看到,已有的数据结构不能很好的平衡静态操作和动态操作的时间开销。
二叉排序树、平衡二叉树
一种简单的方法是采用二叉排序树(也叫二叉搜索树,BST,Binary Search Tree),构造一颗二叉排序树十分简单。一般来讲,大于根节点的放在根节点的右子树上,小于根节点的放在根节点的左子树上(如果等于根节点,则可视情况而定),如果写程序的话,可以采用递归的方式,而且由于不存在重叠子问题的情况,因此递归的性能已经足够好(不考虑栈溢出的情况)。
二叉排序树在通常情况下可以达到O(lgN)的静态、动态操作的时间复杂度,但是存在一种特殊情况,即输入的数据本身就是有序的,这时二叉排序树退化成向量。
为了消除二叉排序树对于输入敏感的特性,引入平衡二叉树,事实上平衡二叉树应该叫平衡二叉排序树也许更合理。它采用递归的方式定义,这里我就不去查书上的标准定义了,只要保证每个节点左子树和右子树的高度差小于等于1就可以了。
平衡二叉树(也叫AVL树)就比较好用了,可以弥补二叉排序树对输入敏感的缺陷,可以确保静态和动态操作的时间复杂度为O(loN)。
B树&B+树
1981年,Bill Gates曾说过这样一段话“640KB is ought to be enough for anybody.”,可能当时intel生产的内存只有640KB,今天看来这句话也许很荒唐,目前好一点的机器都已经达到16GB的内存了,但是事实上这句话仍然有一定的道理。
只要学习过操作系统的人都知道,存储器的访问速度和容量往往成反比(这句话不是很妥当,只要领会意思就好),最快的当然是CPU上的寄存器,然后是cache(多级cache,不同硬件平台不同),然后是内存、外部硬盘等等。当两个处在不同层级上的存储器彼此之间交互数据时(例如内存与硬盘之间),我们称之为I/O,事实上这种I/O操作相当耗时,应该尽可能避免。
B树的出现就是为了解决这个问题,B树由于是多路二叉树,事实上它的高度要远低于二叉平衡树。一般来讲,我们可以认为二叉平衡树每下降一层需要执行一次磁盘I/O操作,以1G数据为例,平均需要30次磁盘I/O才能读取到数据,而B树每下降一层,每个超级结点都会读入多个关键码,需要的磁盘I/O次数小于AVL树,因此B树适用于实现磁盘的读写逻辑。
红黑树
对于向量、列表、树和图来说,它们每次的动态操作都会完全遗忘之前的状态,转而到达全新的状态,这种数据结构称为ephemeral structure。另一种数据结构可以记录某一历史时刻的状态,在访问时可以根据版本好+目标数据进行访问,这种数据结构称为persistent structure。事实上,红黑树可以实现这种对历史版本的记录,我也不懂它为什么有这么奇妙的功能,这里就不再深入研究了,因为我觉得研究明白以后我还是会忘,有机会再看。
结论
回到最初的问题,即面试官提到的问题。我觉得面试官强迫我在B树和红黑树之间选择没有多少道理,因此线程调度的数据量很小,不涉及磁盘I/O的问题,同时线程调度好像也没有记录历史版本的需求,而这两个数据结构的静态和动态操作的时间复杂度一样,空间复杂度也接近,因此它们两个应该差不多才对。话说,它们两个的实现效率都不如斜堆。
二叉排序树、平衡二叉树、B树&B+树、红黑树的设计动机、缺陷与应用场景的更多相关文章
- 1.红黑树和自平衡二叉(查找)树区别 2.红黑树与B树的区别
1.红黑树和自平衡二叉(查找)树区别 1.红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单. 2.平衡 ...
- 数据结构和算法(Golang实现)(29)查找算法-2-3树和左倾红黑树
某些教程不区分普通红黑树和左倾红黑树的区别,直接将左倾红黑树拿来教学,并且称其为红黑树,因为左倾红黑树与普通的红黑树相比,实现起来较为简单,容易教学.在这里,我们区分开左倾红黑树和普通红黑树. 红黑树 ...
- 从二叉搜索树到AVL树再到红黑树 B树
这几种树都属于数据结构中较为复杂的,在平时面试中,经常会问理解用法,但一般不会问具体的实现,所以今天来梳理一下这几种树之间的区别与联系,感谢知乎用户@Cailiang,这篇文章参考了他的专栏. 二叉查 ...
- 从二叉查找树到平衡树:avl, 2-3树,左倾红黑树(含实现代码),传统红黑树
参考:自平衡二叉查找树 ,红黑树, 算法:理解红黑树 (英文pdf:红黑树) 目录 自平衡二叉树介绍 avl树 2-3树 LLRBT(Left-leaning red-black tree左倾红黑树 ...
- 简述树,Trie,Avl,红黑树
树的表示方法 在平时工作中通常有2种方式来表示树状结构,分别是孩子链表示法和父节点表示法.光说名词可能无法让人联系到实际场景中,但是写出代码之后大家一定就明白了. 孩子链表示法,即将树中的每个结点的孩 ...
- 红黑树、B(+)树、跳表、AVL等数据结构,应用场景及分析,以及一些英文缩写
在网上学习了一些材料. 这一篇:https://www.zhihu.com/question/30527705 AVL树:最早的平衡二叉树之一.应用相对其他数据结构比较少.windows对进程地址空间 ...
- 大名鼎鼎的红黑树,你get了么?2-3树 绝对平衡 右旋转 左旋转 颜色反转
前言 11.1新的一月加油!这个购物狂欢的季节,一看,已囊中羞涩!赶紧来恶补一下红黑树和2-3树吧!红黑树真的算是大名鼎鼎了吧?即使你不了解它,但一定听过吧?下面跟随我来揭开神秘的面纱吧! 一.2-3 ...
- 红黑树与AVL树
概述:本文从排序二叉树作为引子,讲解了红黑树,最后把红黑树和AVL树做了一个比较全面的对比. 1 排序二叉树 排序二叉树是一种特殊结构的二叉树,可以非常方便地对树中所有节点进行排序和检索. 排序二叉树 ...
- AVL树、splay树(伸展树)和红黑树比较
AVL树.splay树(伸展树)和红黑树比较 一.AVL树: 优点:查找.插入和删除,最坏复杂度均为O(logN).实现操作简单 如过是随机插入或者删除,其理论上可以得到O(logN)的复杂度,但是实 ...
随机推荐
- 利用mk-table-checksum监测Mysql主从数据一致性操作记录
前面已经提到了mysql主从环境下数据一致性检查:mysql主从同步(3)-percona-toolkit工具(数据一致性监测.延迟监控)使用梳理今天这里再介绍另一种Mysql数据一致性自动检测工具: ...
- js 数组与对象的区别
学习javascript的时候,我曾经一度搞不清楚”数组”(array)和”对象”(object)的根本区别在哪里,两者都可以用来表示数据的集合. 比如有一个数组a=[1,2,3,4],还有一个对 ...
- getRequestDispatcher()和response.sendRedirect()
request.getRequestDispatcher()是请求转发,前后页面共享一个request response.sendRedirect()是重新定向,前后页面不是一个request.
- input标签的美化
css input checkbox和radio样式美化:http://www.haorooms.com/post/css_mh_ck_radio 自定义 css checkbox 样式 :http ...
- awk匹配以aaa开头,以bbb结尾的内容,同时aaa和bbb之间还包含ccc
如果是匹配以A开头,以B结尾的内容,同时A和B之间还包含C的这种怎么做?比如 [root@localhost ~]#cat file aaa grge ddd bbb aaa gege ccc bbb ...
- Nginx+Geoserver部署所遇问题总结
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 该问题的最终解决离不开公司大拿whs先生的指点,先表示感谢. ...
- TCP连接之未连接队列的理解[转]
tcp服务器在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接. 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认 ...
- Jenkins初识
Jenkins Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. 功能 Jenkins功能包括 ...
- 【分布式】ZooKeeper学习之一:安装及命令行使用
ZooKeeper学习之一:安装及命令行使用 一直都想着好好学一学分布式系统,但是这拖延症晚期也是没得治了,所以干脆强迫自己来写一个系列博客,从zk的安装使用.客户端调用.涉及到的分布式原理.选举过程 ...
- CentOS上安装MongoDB速记
测试环境版本CentOS 6.5 先创建安装目标文件夹并进入至该文件夹: mkdir /opt/mongodb cd /opt/mongodb 给mongodb创建用户及用户组: groupadd m ...