树
1、二叉搜索树(BST)
- 「左⼩右⼤」,对于每个节点,整棵左⼦树都⽐该节点的值⼩,整棵右⼦树都⽐该节点的值⼤。
- BST 的中序遍历结果是有序的(升序)
- 缺点:容易退化成一条链,查找的时间复杂度从O(log2N)退化成O(N)
思路
2、平衡二叉树(AVL)
-
在二叉搜索树的基础上加了限制:左右子树的高度差不能超过1
-
每次进行插入/删除操作时,几乎都需要通过旋转操作保持平衡
-
左旋:逆时针旋转两个节点,让一个节点被它的右子节点取代,而这个节点就成了右子节点的左子节点
-
右旋:顺时针旋转两个节点,让一个节点被他的左子节点取代,而这个节点就成了左子节点的右子节点
-
缺点:在插入/删除比较频繁的场景中,需要频繁的旋转操作,这时候AVL的性能大打折扣
3、红黑树(具有自动平衡机制的二叉搜索树,弱平衡二叉树)
(1) 规则
- 节点为红色或者黑色;
- 根节点必须为黑色;叶子节点(null)为黑色;
- 红黑树不会出现连续的红色节点;
- 每个节点到叶子节点的所有路径,都包含相同数目的黑色节点;
- 新加入到红黑树的节点为红色节点;
- 从根节点到叶子节点的最长路径不大于最短路径的2倍
(2) 红黑树的调整情形:插入最多旋转2次,删除最多旋转3次
- 新插入红黑树的节点一定是红色
- 若新插入节点的爸爸是黑色节点,红黑树不需要调整 3
- 若新插入节点的爸爸和它叔叔都是红色节点,红黑树只需要变色,不需要旋转
- 若新插入节点的爸爸是红色,但是它叔叔是黑色(可能为null,但是null是叶子节点,正儿八经的黑色),这时,一定是变色+旋转。
(3) 与AVL树(平衡二叉树)的区别
- 红黑树是弱平衡二叉树,是高度平衡的,插入最多两次旋转,删除最多三次旋转;所以红黑树在查找,插入删除的性能都是O(logn),且性能稳定,所以STL里面很多结构包括map底层实现都是使用的红黑树。
- 红黑树整体性能略优于AVL树(红黑树旋转情况少于AVL树)
- AVL树的时间复杂度虽然优于红黑树,但是对于现在的计算机,cpu太快,可以忽略性能差异
- 红黑树的插入删除比AVL树更便于控制操作
(4)map和unordered_map的底层实现,以及两者的优点和缺点
底层实现
- map是基于红黑树实现的,因此map内部元素排列是有序的
- unordered_map是基于哈希表实现的,因此其元素的排列顺序是杂乱无序的
优缺点
- map结构最大的优点是有序性,其元素的有序性在很多应用中都会简化很多操作;map的查找、删除、增加等一系列操作时间复杂度稳定,都为logn;也正因为操作时间与n有关,n太大的时候会比较慢。
- unordered_map的查找、删除、添加等操作的时间复杂度是常数级的,O©,所以比较快;unordered_map内部基于哈希表,以(key,value)对的形式存储,因此空间占用率高;查找、删除、添加的时间复杂度其实是取决于哈希函数的,有时候不稳定,极端情况下可能为O(n)
(5) 请你回答一下epoll怎么实现的
-Linux epoll机制是通过红黑树和双向链表实现的。
- 首先通过epoll_create()系统调用在内核中创建一个eventpoll类型的句柄,其中包括红黑树根节点和双向链表头节点。
- 然后通过epoll_create()系统调用,向epoll对象的红黑树结构中添加、删除、修改感兴趣的事件,返回0标识成功,返回-1标识失败;
- 最后通过epoll_wait()系统调用判断双向链表是否为空,如果为空则阻塞。当文件描述符状态改变,fd上的回调函数被调用,该函数将fd加入到双向链表中,此时epoll_wait函数被唤醒,返回就绪好的事件。
4、哈夫曼树
(1)定义
- 哈夫曼编码是哈夫曼树的一种应用,广泛用于数据文件压缩。哈夫曼编码算法用字符在文件中出现的频率来建立。
(2)具体算法
- 哈夫曼算法以自底向上的方式构造表示最优前缀码的二叉树T。
- 算法以|C|个叶结点开始,执行|C|-1次的“合并”运算后产生最终所要求的树T。
- 假设编码字符集中每一字符c的频率是f©。以f为键值的优先队列Q用在贪心选择时有效地确定算法当前要合并的2棵具有最小频率的树。
- 一旦2棵具有最小频率的树合并后,产生一棵新的树,其频率为合并的2棵树的频率之和,并将新树插入优先队列Q。经过n-1次的合并后,优先队列中只剩下一棵树,即所要求的树T。
5、B树/B-树
(1)定义
- 一种平衡的多叉树
(2)特征
- 以 一颗m阶(阶:一个节点最多有多少个孩子节点)的B-树为例
- 根结点至少有两个子女;
- 每个非根节点所包含的关键字个数 j 满足:⌈m/2⌉ - 1 <= j <= m - 1.(⌈⌉表示向上取整)
- 有k个关键字(关键字按递增次序排列)的非叶结点恰好有k+1个孩子。
- 所有的叶子结点都位于同一层。
6、 B+树
(1)定义
- B+树是B-树的变体,也是一颗多路搜索树。
(2)特征
- 以 一颗m阶(阶:一个节点最多有多少个孩子节点)的B+树为例
- 每个结点至多有m个子女;
- 非根节点关键值个数范围:⌈m/2⌉ - 1 <= k <= m-1
- 相邻叶子节点是通过指针连起来的,并且是关键字大小排序的。
- 一颗3阶的B+树如下:
(3)B树与B+树的区别
- B+树的层级更少:相较于B树,B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;
- B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
- B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。(B+树相邻的叶子节点之间是通过链表指针连起来的,B-树却不是。)
- B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。(B-树内部节点是保存数据的;而B+树内部节点是不保存数据的,只作索引作用,它的叶子节点才保存数据。查找过程中,B-树在找到具体的数值以后就结束,而B+树则需要通过索引找到叶子结点中的数据才结束)
- B-树中任何一个关键字出现且只出现在一个结点中,而B+树可以出现多次。
- 而B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点本身存有关键字其数据的地址,所以这种数据检索的时候会要比B+树快。