1.8 HashMap源码

1、红黑树

《算法导论》中对于红黑树的定义:

  • 每个节点或是红的,或是黑的
  • 根节点是黑的
  • 每个叶节点是黑色(叶节点用Null来表示 Show Null Leaves) 【这里的叶子结点是Null的结点】
  • 如果一个结点是红色,则它的两个儿子都是黑色(不能出现连续的红节点)
  • 对每个结点,从该节点到其子孙结点的所有路径上包含相同数目的黑节点(黑节点平衡)

NULL结点

  1. 插入新节点:默认是红色
  2. 变色操作
  3. 例如:依次插入10、20、30

会进行 变色 + 左旋 

红黑树新插入结点p:

p的父节点是黑色,则不用进行调整;

p的父节点是红色:

  • 叔叔结点是空的(空节点默认是黑色),则 旋转(优先旋转祖孙三代) + 变色(G和P都变色

  • 叔叔结点 25 是红色,则 父节点 + 叔叔结点 变为黑色,祖父结点变为红色

 ====> 

 

  • 叔叔结点 25 是黑色, 左旋 + 变色

 ===> ==>

左旋===> 变色===> 

插入结点4(调整祖孙三代)右旋==>变色 ==> 

 

再插入结点6  ===> 结点5先左旋,结点10再右旋 ===>

  ===> 结点10再右旋

2、HashMap

2.1 TreeNode - 红黑树的结点 

prev 双向链表

2.2 put

2.3 红黑树的插入:balanceInsertion(TreeNode<K,V> root, TreeNode<K,V> x)

root:根节点;x:带插入的结点

新节点x 默认为红色;

xp表示x的父节点,xpp表示x的祖父结点,xppl表示xpp的左孩子结点,xppr表示xpp的右孩子结点;

3、JDK1.8 hashmap源码

3.1 put

首先,对key进行哈希(或运算和右移运算),计算key应该放到哪个数组的位置。

Node:

put关键方法:putVal

resize()方法:既包括对数组的初始化,又包括对数组的扩容。

当存在相同的key时,那么更新结点e时,会返回原来结点的oldValue。

使用尾插法:p.next = newNode(hash, key, value, null)

插入之后,必须进行判断 是否树化treeifyBin(tab, hash)

if(binCount >= TREEIFY_THRESHOLD - 1)

当 binCount >= 7,也即是链表长度 >= 8 会树化

链表转化为红黑树:

双向链表:

判断数组的大小若小于64,则不会树化,只会resize() --> 扩容

树化:将原来链表的Node 重新构造为 TreeNode,并且生成双向链表。hd 表示生成的双向链表的第一个元素。

树化方法:hd.treeify(tab)

遍历双向链表,其第一个结点作为树的root结点,下一个结点插入到红黑树中。随着红黑色结点的增加,root结点会发生改变。

树化插入结点时的比较规则: 

  • hashcode 先比较key的哈希值 :(ph = p.hash)  h进行比较
  • compareto()
  • getClass().getName  compareTo
    • System.identityHashCode(a)

moveRootToFront:将红黑树的root结点移动到hashmap的tab[i]链表头,替换掉原来的链表;同时将双向链表的root结点移动至链表的第一个结点位置。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值