TreeMap的底层实现(红黑树)

1、TreeMap数据结构

TreeMap的定义如下:

public class TreeMap
extends AbstractMap
implements NavigableMap, Cloneable, java.io.Serializable

TreeMap继承AbstractMap,实现NavigableMap、Cloneable、Serializable三个接口。其中AbstractMap表明TreeMap为一个Map即支持key-value的集合

//比较器,因为TreeMap是有序的,通过comparator接口我们可以对TreeMap的内部排序进行精密的控制
        private final Comparator<? super K> comparator;
        //TreeMap红-黑节点,为TreeMap的内部类
        private transient Entry<K,V> root = null;
        //容器大小
        private transient int size = 0;
        //TreeMap修改次数
        private transient int modCount = 0;
        //红黑树的节点颜色--红色
        private static final boolean RED = false;
        //红黑树的节点颜色--黑色
        private static final boolean BLACK = true;
对于叶子节点Entry是TreeMap的内部类,它有几个重要的属性:

//键
        K key;
        //值
        V value;
        //左孩子
        Entry<K,V> left = null;
        //右孩子
        Entry<K,V> right = null;
        //父亲
        Entry<K,V> parent;
        //颜色
        boolean color = BLACK;

2、Java 中TreeMap是如何通过put、deleteEntry两个来实现红黑树增加、删除节点的。

TreeMap put()方法实现分析

在TreeMap的put()的实现方法中主要分为两个步骤,第一:构建排序二叉树,第二:平衡二叉树。

对于排序二叉树的创建,其添加节点的过程如下:

以根节点为初始节点进行检索。
与当前节点进行比对,若新增节点值较大,则以当前节点的右子节点作为新的当前节点。否则以当前节点的左子节点作为新的当前节点。
循环递归2步骤知道检索出合适的叶子节点为止。
将新增节点与3步骤中找到的节点进行比对,如果新增节点较大,则添加为右子节点;否则添加为左子节点。
按照这个步骤我们就可以将一个新增节点添加到排序二叉树中合适的位置

3、红黑树的基本概念。

每个节点都只能是红色或者黑色
根节点是黑色
每个叶节点(NIL节点,空节点)是黑色的。
如果一个结点是红的,则它两个子节点都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。
从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

4.红黑树的定义(特性)

1. 根节点是【黑色】
2. 每个节点要么是【黑色】要么是【红色】
3. 每个【红色】节点的两个子节点一定都是【黑色】
4. 每个叶子节点(NIL)都是【黑色】
5. 任意一个节点的路径到叶子节点所包含的【黑色】节点的数量是相同的---这个也称之为【黑色完美平衡】
6. 新插入的节点必须是【红色】->为什么?如果新插入的节点是【黑色】,那不管是在插入到那里,一定会破坏黑色完美平衡的,因为任意一个节点的路径到叶子节点的黑色节点的数量肯定不一样了(第 6 点我自己加的,实际特性的定义是前 5 个)

5.红黑树与AVL树的比较

1. AVL树的时间复杂度优于红黑树,但是对于现在的计算机,这种差别可以忽略
2. 红黑树的插入删除比AVL树更便于控制操作。
3. 红黑树整体性能略优于AVL树。(红黑树旋转情况少于AVL树)。这点是非常重要的
4. 如果是在查询很多增删少的情况下 AVL 树还是优于红黑树的,如果增删比较频繁,那红黑树绝对是完美的一种选择

红黑树在添加和删除节点的时候是靠什么来维持平衡的呢?那就是左旋右旋变色

左旋右旋变色的定义 (旋那边 另一半的的 反方向子节点给对方 )

左旋:以某个节点作为固定支撑点(围绕该节点旋转),其右子节点变为旋转节点的父节点,右子节点的左子节点变为旋转节点的右子节点,左子节点保持不变

右旋: 以某个节点作为固定支撑点(围绕该节点旋转),其左子节点变为旋转节点的父节点,左子节点的右子节点变为旋转节点的左子节点,右子节点保持不变
 
变色:节点的颜色由红色变成黑色,或者是由黑色变成红色

左旋:

R 表示旋转节点,没有别的特殊的含义,以下的节点都是没有任何实际意义的
TreeMap的底层实现(红黑树)_第1张图片
假设这是一个带旋转的树,假设以 R 点为旋转节点,根据左旋特性第一点:旋转节点的右子节点变为旋转节点的父节点
TreeMap的底层实现(红黑树)_第2张图片
直接找到旋转节点,然后将旋转节点的右子节点设置成旋转节点的父节点。下一步,将旋转节点右子节点左子节点设置为旋转节点的右子节点,再看下图
TreeMap的底层实现(红黑树)_第3张图片
右旋:
TreeMap的底层实现(红黑树)_第4张图片
以 R 为旋转节点进行右旋,首先将 R 节点的左子节点 L 设置成 R 的父节点,完事后是下面这样子的
TreeMap的底层实现(红黑树)_第5张图片
接着是第二小点,将 R 的左节点(L)的右子节点(LR)设置成 R 的左子节点,那根据上图应该直接就能想象出来了,那就是下面这样子的
TreeMap的底层实现(红黑树)_第6张图片

你可能感兴趣的:(面试题,java)