java 集合 底层源码分析( jdk 1.8 )

ArrayList 集合底层原理

原理:
① 利用空参创建的集合,在内存中是默认长度为0的
② 添加第一个元素的时候,底层会创建一个长度为10的数组
③ 存满时,会扩容1.5倍
④ 如果一次添加多个元素,1.5倍还放不下,新创建的数组以实际为准

源码分析

  1. ArrayList 的空参构造
public ArrayList() {
	// 这个数组是空数组
	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

elementDate 是java底层的数组

// 可以看到,elementData是一个数组对象
transient Object[] elementData;

DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是一个空数组

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

size 默认是 0

private int size;
  1. 添加元素

    e 代表添加的元素
    size 默认是 0 代表集合长度和 元素应存入的位置
public boolean add(E e) {
	// 调用方法,进入ensureCapacityInternal 传递长度为 1
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    // 将当前元素传给size位置,并移动到下一个位置
    elementData[size++] = e;
    // 返回添加成功
    return true;
}
  1. ensureCapacityInternal 这个方法记录修改次数,和显示容量

    minCapacity  是最小容量,传递的值为 1
    modCount++ 是记录修改次数
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    // 最小容量 - 集合长度 = 1   1 > 0 成立
    if (minCapacity - elementData.length > 0)
    	// 调用grow 方法 把最小容量传递过去
        grow(minCapacity);
}
  1. 扩容 grow

    minCapacity  是最小容量,传递的值为 1
    oldCapacity 是原来的容量 老容量 这里为0
    newCapacity 是新的容量 这里是0
    MAX_ARRAY_SIZE int 包装类Integer - 8 2147483647 - 8
private void grow(int minCapacity) {
    // overflow-conscious code
    // 老容量 = 集合的长度 初始为0   0
    int oldCapacity = elementData.length;
    // 新容量 = 老容量 + 老容量 右移一位 还是0   0
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 如果新容量 - 最小容量 < 0 就把最小容量给新容量 实现扩容
    if (newCapacity - minCapacity < 0)
    	// 容量扩容 至原来的1.5倍
        newCapacity = minCapacity;
    // 如果新容量 - 最大数 (2147483647 - 8) > 0  就直接扩大最大数
    if (newCapacity - MAX_ARRAY_SIZE > 0)
    	// 
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    // 拷贝数组到新的数组
    elementData = Arrays.copyOf(elementData, newCapacity);
}
  1. hugeCapacity 判断传递最大数
    minCapacity                最小容量
    MAX_ARRAY_SIZE    2147483647 - 8 )
    Integer.MAX_VALUE   0x7fffffff 转换为10进制 2147483647
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
    	// 如果是负数,这里报错,应该是内存溢出
        throw new OutOfMemoryError();
    // 如果是大于 2147483647 - 8 
    // 就传递 2147483647 否则传递2147483647 - 8
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

LinkedList 集合(底层双链表)

源码分析
创建一个LinkdList 集合

LinkedList<string> list = new Linkedlist<>();

内存会创建一个包含头节点和尾结点的空间
在这里插入图片描述

  1. 结点对象
private static class Node<E> {
	// 记录我要存储的数据
    E item;
    // 记录下一个结点的地址值
    Node<E> next;
    // 记录上一个结点的地址值
    Node<E> prev;
	// 传递数值
    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}
  1. 三个成员变量
	// 集合的长度 也表示结点的总个数
    transient int size = 0;
	// 头结点
    transient Node<E> first;
	// 尾结点
    transient Node<E> last;
  1. add 添加方法
// e 表示元素
public boolean add(E e) {
	// 调用linkLast 传递元素
    linkLast(e);
    return true;
}
  1. linkLast 创建结点
void linkLast(E e) {
	// last 初始值是null 集合尾结点
    final Node<E> l = last;
    // 并创建一个结点 赋值给 newNode  
    // new Node<>(l, e, null); 上一个结点 元素 下一个结点  null e null
    final Node<E> newNode = new Node<>(l, e, null);
    // 把刚刚创建的结点newNode 赋值给 集合last尾结点 last 
    last = newNode; // 每次都会把新结点赋值
    // 如果 l 等于空
    if (l == null)
    	// 把 newNode 赋值给 集合头节点
        first = newNode;
    else
    	// 把 新结点newNode 赋值给 当前l.next 也就是上一个尾结点
        l.next = newNode;
    // 集合长度+1
    size++;
    modCount++; // 修改次数
}

Iterator 迭代器源码分析

Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String str = it.next();
    System.out.println(str);
}
  1. 首先创建一个迭代器 创建好之后 就会new Itr
public Iterator<E> iterator() {
    return new Itr();
}
  1. 就会在内部类创建一个迭代器
private class Itr implements Iterator<E> {
		// 表示光标 当前索引
        int cursor;       // index of next element to return
        // 表示上一个索引,光标
        int lastRet = -1; // index of last element returned; -1 if no such
        // modCount 集合变化的次数 删除和添加都会自增 
        // expectedModCount 创建迭代器的时候就会初始次数 
        int expectedModCount = modCount;
		// 空参
        Itr() {}
		// 判断下一个索引是否大于等于迭代器的最大元素
		// 如果大于等于返回false
        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        // 元素光标移动
        public E next() {
        	// 当前集合中最新的变化次数跟一开始记录的次数是否相同,
			// 如果相同,证明当前集合没有发生改变
			// 如果不一样,证明在送代器遍历集合的过程中,
			// 使用了集合中的方法添加/删除了元素
            checkForComodification();
            // 当前光标赋值给 i
            int i = cursor;
            // 当前光标是否大于等最大元素
            if (i >= size)
            	// 成立,报错越界
                throw new NoSuchElementException();
            // 把当前底层的数组赋值给 elementData 
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
			// 光标移动下一个位置
            cursor = i + 1;
            // 上一个元素 等于 i 当前光标 并添加元素
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
        	// expectedModCount 初始修改次数 和 每一次相比较
            if (modCount != expectedModCount)
            	// 并发异常报错
                throw new ConcurrentModificationException();
        }
    }

HashSet 底层原理

Hashset集合底层原理
HashSet集合底层采取哈希表存储数据
哈希表是一种对于增删改查数据性能都较好的结构

哈希表组成
JDK8之前:数组+链表
JDK8开始:数组+链表+红黑树

  1. 创建一个默认长度为16,默认加载因素为0.75的数组,数组名table
HashSet<String> hm = new HashSet<>();
  1. 根据元素的哈希值跟数组的长度计算出应存入的位置
int index = (数组长度 - 1) & 哈希值;
  1. 判断当前位置是否为 null,如果为 null 直接存入
  2. 如果不为 null,表示有元素,则调用equals方法比较属性值
  3. 一样:不存 不一样:存入数组形成链表
    JDK8以前:新元素存入数组,老元素挂在新元素下面
    JDK8以后:新元素直接挂在老元素下面
  4. 会依次和当前数组位置的所有元素依次比较

细节:当数组存了 16 * 0.75 = 12 个元素的时候,数组就会扩容2倍
当链表长度大于8而且数组长度大于等于64,链表就会自动转换红黑树

如果集合中存入的是自定义对象,必须重写hashCode和equals

HashMap 底层原理

常规说明:
这个C表示类名
下面的M表示方法,当方法名和类名相同时,代表构造方法,其他都是成员方法

在这里插入图片描述

后面的向上的箭头表示,重写的父类方法,后面是父类类名
在这里插入图片描述

后面的向右的箭头表示,继承过来的方法

在这里插入图片描述

像这种 f 开头的黄色的,代表是成员变量或者是常量

在这里插入图片描述
这个绿色的 i 表示接口来自Map
蓝色的是类,最小边都是内部类
在这里插入图片描述



在HashMap中,每一个元素都是一个Node节点

// 实现 Map 里面的 Entry对象(链表数组)
static class Node<K,V> implements Map.Entry<K,V> {
	// 根据键计算出来的哈希值
   final int hash;
   // 键
   final K key;
   // 值
   V value;
   // 在链表中记录下一个节点的地址值
   Node<K,V> next;
}

红黑树的每一个节点叫做 TreeNode

// TreeNode 继承与 LinkedHashMap 的 Entry对象
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
	// 父节点的地址值
    TreeNode<K,V> parent;  // red-black tree links
    // 左子节点
    TreeNode<K,V> left;
    // 右子节点
    TreeNode<K,V> right;
    TreeNode<K,V> prev;    // needed to unlink next upon deletion
    // 当前节点的颜色,false 黑色
    boolean red;

介绍一些常量和变量:

表示是 Node元素的数组,存入的都是Node对象

transient Node<K,V>[] table;

默认的数组长度是 16,1左移4位

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

默认的加载因子是0.75,扩容时机数组乘以0.75,就是12,每次扩容是两倍

static final float DEFAULT_LOAD_FACTOR = 0.75f;

数组最大的长度,1左移30位 1073741824

static final int MAXIMUM_CAPACITY = 1 << 30;

下面是HashMap的构造方法

无参构造

public HashMap() {
	// 把默认加载因子赋值给成员变量,loadFactor, 这个时候没有创建数组
	this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

添加元素
返回给真正的添加数据 putVal

  1. 第一个参数获取哈希值
  2. 第二个是键
  3. 第三个是值
  4. 第四个表示当前的数据是否保留,判断是否覆盖
  5. 第五个没太大关系
// k 键 v 值
public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

过程:

  1. tab 局部变量,表示哈希表中的数组的地址值。
  2. p 临时的第三方变量,记录键值对对象的地址值
  3. n 表示数组的长度
  4. i 表示索引
 Node<K,V>[] tab; Node<K,V> p; int n, i;
  1. tab = table 将数组的地址赋值给tab
  2. n = tab.length 将数组的长度赋值给n
  3. 然后判断数组是否等于 0 或者 数组等于 null
  4. 调用resize方法,把数组长度再次赋值给 n
if ((tab = table) == null || (n = tab.length) == 0)
	n = (tab = resize()).length;
  1. i = (n - 1) & hash
  2. n - 1 是数组 和 键的哈希值进行计算,计算出应存入的位置,并赋值给 i
  3. p = tab[i] 获取元素中的数据赋值给 p
  4. 如果p 为 null else不执行
if ((p = tab[i = (n - 1) & hash]) == null)
	// 把要添加的 哈希值,键,值,空 赋值给newNode
	// 返回一个node对象,给当前索引
	tab[i] = newNode(hash, key, value, null);
else {
	// 键值对对象
    Node<K,V> e; K k;
    // p.hash == hash 数组中的哈希值  和 当前添加的哈希值 是否相等
    // 如果不相等,返回false
    if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))
        e = p;
    // 判断数组中的获取出来的键值对是否是红黑树的节点
    else if (p instanceof TreeNode)
    	// 如果是 调用方法 putTreeVal,把当前节点按照红黑树的规则添加到树中
        e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
    else {
    	// 如果不是,就挂链表
        for (int binCount = 0; ; ++binCount) {
        	// 判断当前 p 的下一个节点是否等于 null 并赋值给 e
            if ((e = p.next) == null) {
            	// 如果等于空,直接把这个对象,赋值给p的下一个节点,形成链表
                p.next = newNode(hash, key, value, null);
                // 判断当前链表长度是否大于8,就会调用 treeifyBin
                if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                	// 进入treeifyBin还会继续判断
                	//如果数组长度大于64,就转红黑树
                    treeifyBin(tab, hash);
                // 跳出循环
                break;
            }
            // 如果当前元素的哈希 和 p元素的下一个元素(就是链表下面的)
            // 哈希值对比,不一样就false  e.hash == hash
            // 如果哈希值一样,就会调用equals方法进行比较 key.equals(k)
            if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
            // 成立就跳出
                break;
            p = e;
        }
    }
    // 如果e为null,表示当前不需要覆盖元素
    // 否则覆盖
    if (e != null) { // existing mapping for key
    	// 当前元素的value 赋值给 老的value
         V oldValue = e.value;   
         // 取反就是true  
         if (!onlyIfAbsent || oldValue == null)
         	// 把新的值,赋值给老的元素value
             e.value = value;
         afterNodeAccess(e);
         // 返回老的值
         return oldValue;
     }
  1. threshold 就是数组长度 * 0.75,哈希表的扩容时机
  2. ++size 默认是0,先+1,用 1 > 扩容时机吗 threshold默认是12
  3. return null; 表示本次添加数据,没有覆盖元素
++modCount;
if (++size > threshold)
    resize();
afterNodeInsertion(evict); // 暂时
return null;

resize方法

  1. 如果当前是第一次添加数据,底层会创建一个长度为16 ,加载因子为0.75的数组
  2. 如果不是第一次添加数据,会看数组中元素是否达到扩容的条件
  3. 如果没有达到条件,底层不做任何事情
  4. 如果达到了扩容条件,底层会把数组扩容为原先的两倍,并把数据转移到新的哈希表中
final Node<K,V>[] resize() {
	// 把数组地址赋值给oldTab
    Node<K,V>[] oldTab = table;
    // 如果数组是null 就 返回0,否则,返回长度
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int oldThr = threshold;
    int newCap, newThr = 0;
    // 判断oldCap 如果大于0
    if (oldCap > 0) {
        if (oldCap >= MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            newThr = oldThr << 1; // double threshold
    }
    else if (oldThr > 0) // initial capacity was placed in threshold
        newCap = oldThr;
    else {         // zero initial threshold signifies using defaults
    	// 如果小于0,就把默认值 16 赋值给 newCap 
        newCap = DEFAULT_INITIAL_CAPACITY;
        // 把加载因子 * 默认长度16 赋值给newThr (扩容的意思)
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    if (newThr == 0) {
        float ft = (float)newCap * loadFactor;
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    threshold = newThr;
    @SuppressWarnings({"rawtypes","unchecked"})
    // new 一个node 创建一个数组长度是 newCap 赋值给 newTab
    Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    // 赋值给 数组 table
    table = newTab;
    if (oldTab != null) {
        for (int j = 0; j < oldCap; ++j) {
            Node<K,V> e;
            if ((e = oldTab[j]) != null) {
                oldTab[j] = null;
                if (e.next == null)
                    newTab[e.hash & (newCap - 1)] = e;
                else if (e instanceof TreeNode)
                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                else { // preserve order
                    Node<K,V> loHead = null, loTail = null;
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    do {
                        next = e.next;
                        if ((e.hash & oldCap) == 0) {
                            if (loTail == null)
                                loHead = e;
                            else
                                loTail.next = e;
                            loTail = e;
                        }
                        else {
                            if (hiTail == null)
                                hiHead = e;
                            else
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } while ((e = next) != null);
                    if (loTail != null) {
                        loTail.next = null;
                        newTab[j] = loHead;
                    }
                    if (hiTail != null) {
                        hiTail.next = null;
                        newTab[j + oldCap] = hiHead;
                    }
                }
            }
        }
    }
    return newTab;
}

newNode方法

  1. 就是创建了一个Node对象,进行赋值操作并返回
Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
	return new Node<>(hash, key, value, next);
}

TreeMap 底层原理

先认识一下 每个节点就是 Entry

static final class Entry<K,V> implements Map.Entry<K,V> {
	// 键
    K key;
    // 值
    V value;
    // 左子节点地址值
    Entry<K,V> left;
    // 右子节点地址值
    Entry<K,V> right;
    // 父节点的地址值
    Entry<K,V> parent;
    boolean color = BLACK;

    /**
     * Make a new cell with given key, value, and parent, and with
     * {@code null} child links, and BLACK color.
     */
    Entry(K key, V value, Entry<K,V> parent) {
        this.key = key;
        this.value = value;
        this.parent = parent;
    }

    /**
     * Returns the key.
     *
     * @return the key
     */
    public K getKey() {
        return key;
    }

    /**
     * Returns the value associated with the key.
     *
     * @return the value associated with the key
     */
    public V getValue() {
        return value;
    }

    /**
     * Replaces the value currently associated with the key with the given
     * value.
     *
     * @return the value associated with the key before this method was
     *         called
     */
    public V setValue(V value) {
        V oldValue = this.value;
        this.value = value;
        return oldValue;
    }

    public boolean equals(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Map.Entry<?,?> e = (Map.Entry<?,?>)o;

        return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
    }

    public int hashCode() {
        int keyHash = (key==null ? 0 : key.hashCode());
        int valueHash = (value==null ? 0 : value.hashCode());
        return keyHash ^ valueHash;
    }

    public String toString() {
        return key + "=" + value;
    }
}

还有两个静态常量

redfalse表示红色
blacktrue 表示黑色
private static final boolean RED   = false;
private static final boolean BLACK = true;

还有静态对象

// 表示比较的规则
private final Comparator<? super K> comparator;
// 表示根节点
private transient Entry<K,V> root;
// 表示集合的长度,也表示红黑树中节点的个数
private transient int size = 0;

当我们利用空参构造创建对象时,表示没有传递规则

public TreeMap() {
	// comparator 就是比较器
    comparator = null;
}

当我们利用有参构造创建对象时,表示传递规则,规则就是我们传递的比较器对象

public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}

添加元素的流程

调用put方法

// 参数一,键,参数二,值
public V put(K key, V value) {
	// 调用 put 重载方法
    return put(key, value, true);
}

调用 put 重载方法

参数1
参数2
参数3是否覆盖默认为 true
private V put(K key, V value, boolean replaceOld) {
	// 获取根节点(root)的地址值,赋值给 t
	// 第一次为null
    Entry<K,V> t = root;
    // 判断 t 是否 为 null
    // 如果是第一次添加,就会把当前元素作为根节点
    // 如果不是第一次添加,就会不执行
    if (t == null) {
    	// 方法底层会创建一个entry对象,把它当作根节点
        addEntryToEmptyMap(key, value);
        // 返回null,表示没用覆盖任何元素
        return null;
    }
    // 表示两个元素的键比较之后的结果
    int cmp;
    // 当前要添加节点的父节点
    Entry<K,V> parent;
    // 表示当前比较规则
    //如果我们采取的默认自然排序,此时comparator为null,cpr 也是null
    //如果我们采取的比较器排序方式,此时comparator记录的就是比较器
    Comparator<? super K> cpr = comparator;
    // 判断是否有比较器对象
    // 传递了比较器,就执行if,没有就是else
    if (cpr != null) {
        do {
        	// 把当前节点赋值给父节点
            parent = t;
            // 调用传入的比较器,比较一下
            cmp = cpr.compare(key, t.key);
            if (cmp < 0)
           		// 负数。继续调左边
                t = t.left;
            else if (cmp > 0)
            	// 正数调用右边
                t = t.right;
            else {
            //为0覆盖
                V oldValue = t.value;
                if (replaceOld || oldValue == null) {
                    t.value = value;
                }
                return oldValue;
            }
        } while (t != null);
    } else {
        Objects.requireNonNull(key);
        @SuppressWarnings("unchecked")
        // 把键进行强转,强转成Comparable类型的
        // 要求,键必须实现Comparable接口,如果没有实现这个接口
        // 此时在强转的时候就会报错
        Comparable<? super K> k = (Comparable<? super K>) key;
        do {
        	// 把根节点赋值给当前节点,当作当前节点的父节点
            parent = t;
            // 调用比较器对象,比较这两个的大小关系
            cmp = k.compareTo(t.key);
            //如果比较结果为负数
            if (cmp < 0)
            	// 那就继续到根节点的左边去找
                t = t.left;
            // 如果比较的为正数
            else if (cmp > 0)
            	// 那就到根节点的右边去找
                t = t.right;
            else {
            	// 如果比较的结果为0,那会覆盖
            	// 将当前节点的值,赋值给oldValue 
                V oldValue = t.value;
                // 如果replaceOld 或者oldValue 等于空
                if (replaceOld || oldValue == null) {
                	// 就把当前值付给t.value
                    t.value = value;
                }
                // 返回之前的值
                return oldValue;
            }
          // 判断当前t是不是null
        } while (t != null);
    }
    // 把当前节点按照比较器规则添加
    addEntry(key, value, parent, cmp < 0);
    return null;
}

addEntryToEmptyMap 方法

private void addEntryToEmptyMap(K key, V value) {
	// 创建比较器,把 key 和 key 去比较,第一次的时候,key肯定是一样的
    compare(key, key); // type (and possibly null) check
    // 创建 entry 对象,把元素赋值给根节点
    root = new Entry<>(key, value, null);
    //长度 为1
    size = 1;
    modCount++;
}

添加的位置

private void addEntry(K key, V value, Entry<K, V> parent, boolean addToLeft) {
		//new一个entry对象赋值给e
       Entry<K,V> e = new Entry<>(key, value, parent);
       //如果添加到左边就把 e赋值给parent.left
       if (addToLeft)
           parent.left = e;
       else
       //如果添加到左边就把 e赋值给 parent.right
           parent.right = e;
       // 添加完节点要按照红黑树规则进行调整
       fixAfterInsertion(e);
       size++;
       modCount++;
   }

红黑规则进行调整

x.parent.color获取父节点的颜色
parentOf(parentOf(x)获取父节点的父节点
leftOf获取左节点
private void fixAfterInsertion(Entry<K,V> x) {
	//因为红黑树的节点默认是红色的
    x.color = RED;
	//判断是不是空,判断是不是根节点,判断.color == RED
    while (x != null && x != root && x.parent.color == RED) {
    	// 判断当前节点的父亲节点 == 左子节点的爷爷节点
        if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
            Entry<K,V> y = rightOf(parentOf(parentOf(x)));
            if (colorOf(y) == RED) {
                setColor(parentOf(x), BLACK);
                setColor(y, BLACK);
                setColor(parentOf(parentOf(x)), RED);
                x = parentOf(parentOf(x));
            } else {
                if (x == rightOf(parentOf(x))) {
                    x = parentOf(x);
                    rotateLeft(x);
                }
                setColor(parentOf(x), BLACK);
                setColor(parentOf(parentOf(x)), RED);
                rotateRight(parentOf(parentOf(x)));
            }
        } else {
            Entry<K,V> y = leftOf(parentOf(parentOf(x)));
            if (colorOf(y) == RED) {
                setColor(parentOf(x), BLACK);
                setColor(y, BLACK);
                setColor(parentOf(parentOf(x)), RED);
                x = parentOf(parentOf(x));
            } else {
                if (x == leftOf(parentOf(x))) {
                    x = parentOf(x);
                    rotateRight(x);
                }
                setColor(parentOf(x), BLACK);
                setColor(parentOf(parentOf(x)), RED);
                rotateLeft(parentOf(parentOf(x)));
            }
        }
    }
    root.color = BLACK;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值