这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战
一、前言
红黑树是于 1972 年发明的, 当时称为对称 二叉 B 树, 1978 年得到优化, 正式命名为红黑树。
它的主要特征是在每个节点上增加一个属性来表示节点的颜色, 可以是红色, 也可以是黑色。
红黑树在本质上还是二叉查找树,它额外引入 5个约束条件:
- 节点只能是红色或黑色
- 根节点必须是黑色
- 所有
NIL节点都是黑色的。(NIL,即叶子节点下挂的两个虚节点,树尾端) - 一条路径上不能出现相邻的两个红色节点
- 在任何递归子树内,根节点到叶子节点的所有路径上包含相同数目的黑色节点
Tips:有红必有黑,红红不相连 若一个树的左节点或右节点不存在,则均认定为黑色
上述5个约束条件保证了以下操作最坏时间复杂度为 O(log(n)):
- 新增
- 删除
- 查找
1. 红黑树 与 AVL 树比较
处于业务场景比较:
- 如果查找次数主导树的更新次数:
AVL树更适合。
AVL树比红黑树保持更加严格的平衡规则,在AVL树中查找通常更快,但这是以更多旋转操作导致更慢的插入和删除为代价的。
- 如果更新次数主导树的查找次数:红黑树更适合。
而
HashMap最初是数组和链表,只有在频繁的插入导致冲突之后才会升级为红黑树,因此可以大概率判断HashMap如果发生了升级则添加和删除应该是比较频繁的,因此红黑树更合适一些。
对红黑树与 AVL 树同时进行以下操作:按顺序依次插入 36、 34、 37、 33、 35、32:
左侧
AVL树的绝对平衡, 以及右侧红黑树的相对平衡。
2. TreeMap
-
TreeMap底层是基于红黑树做的数据结构。 -
TreeMap是按照Key的排序结果来组织内部结构的Map类集合, 它改变了Map类散乱无序的形象。
在 TreeMap 的接口继承树申, 有两个与众不同的接口 SortedMap 和 NavigableMap:
SortedMap接口:表示它的Key是有序不可重复的, 支持获取头尾Key-Value元素, 或者根据Key指定范围获取子集合等。
插入的
Key必须实现Comparable或提供额外的比较器Comparator, 所以Key不允许为null, 但是Value可以;
-
NavigableMap接口:继承了SortedMap接口 , 根据指定的搜索条件返回最匹配的Key-Value元素 。不同于
HashMap,TreeMap并非定要覆写hashCode和equals方法来达到Key去重的目的。
二、自定义排序规则
TreeMap 默认是按照 Key 大小来排序:
先来一个 demo ,看看 TreeMap 排序效果:
public class Test {
public static void main(String[] args) {
Map<Integer, String> map = new TreeMap<>();
map.put(2, "牛yyds");
map.put(1, "哈xswl");
map.put(10, "牛哇牛哇");
map.put(4, "牛yyds-1");
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry);
}
}
}
输出结果:
1=哈xswl
2=牛yyds
4=牛yyds-1
10=牛哇牛哇
当然可以指定排序规则,倒排 - 从大到小:
public class Test {
public static void main(String[] args) {
Map<Integer, String> map = new TreeMap<>((o1, o2) -> o2 - o1);
map.put(2, "牛yyds");
map.put(1, "哈xswl");
map.put(10, "牛哇牛哇");
map.put(4, "牛yyds-1");
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry);
}
}
}
输出结果如下:
10=牛哇牛哇
4=牛yyds-1
2=牛yyds
1=哈xswl