文章目录
1.HashMap的基本思想简述2.成员变量介绍3.构造函数介绍4.其他方法介绍5.红黑树存储结构介绍
1.HashMap的基本思想简述
HashMap是通过数组+链表+红黑树的方式存储键值对,他会根据要存储的键值对的hash值来确定该键值对在数组中的插入位置,如果该位置已经有元素,则插入到该元素的后面,当链表长度到达8并且数组的长度超过64时,链表会自动转化成为红黑树存储,这是为了保证查找效率,红黑树的查找效率为O(logn)。HashMap是无序的。HashMap可以接受null的键值。
2.成员变量介绍
DEFAULT_INITIAL_CAPACITY:默认初始容量为16,这里需要说明hashMap的容量必须要为2的幂数,这是因为以下几点原因(欢迎补充):
我们在计算新的键值对插入的位置时是根据hash值来确定,具体的公式为如下所示,其中n为map的容量,因此减1之后为若干个连续的1,与hash值做&运算时,不会超过map的容量&运算快于取模运算若n满足是2的幂数,则满足了 (n - 1) & hash = hash % n 这个公式 DEFAULT_LOAD_FACTOR:默认负载因子,当map的size超过容量*负载因子时,map会自动扩容为原来的两倍,这个负载因子是经过许多试验的出来的最优值,基本不用修改。entrySet:键值对集合loadFactor:负载因子MAXIMUM_CAPACITY:最大容量 为1 << 30TREEIFY_THRESHOLD:链表转化为红黑树的最小长度UNTREEIFY_THRESHOLD:红黑树转化为链表的最小长度modCount:实现fail-Fast机制size:map中的元素的个数table:存储元素的数组,数据类型为Node<k, v>
static class Node<K,V> implements Map.Entry<K,V> {
final int hash
;
final K key
;
V value
;
Node
<K,V> next
;
Node(int hash
, K key
, V value
, Node
<K,V> next
) {
this.hash
= hash
;
this.key
= key
;
this.value
= value
;
this.next
= next
;
}
public final K
getKey() { return key
; }
public final V
getValue() { return value
; }
public final String
toString() { return key
+ "=" + value
; }
public final int hashCode() {
return Objects
.hashCode(key
) ^ Objects
.hashCode(value
);
}
public final V
setValue(V newValue
) {
V oldValue
= value
;
value
= newValue
;
return oldValue
;
}
public final boolean equals(Object o
) {
if (o
== this)
return true;
if (o
instanceof Map.Entry) {
Map
.Entry
<?,?> e
= (Map
.Entry
<?,?>)o
;
if (Objects
.equals(key
, e
.getKey()) &&
Objects
.equals(value
, e
.getValue()))
return true;
}
return false;
}
}
threshold:他的值为 loadFactor*Capacity,当size超过这个值时,map就会自动扩容
3.构造函数介绍
public HashMap(int initialCapacity, float loadFactor):通过给定的容量和负载因子来创建一个map,查看一下源码我们注意到map的最大容量是MAXIMUM_CAPACITY,如果你给定的初始容量超过了这个值,则map会自动转化为MAXIMUM_CAPACITY,其次我们注意到this.threshold = tableSizeFor(initialCapacity) 这段代码,我们在前面提到threshold的值是capacity*loadFactor,这里明显与我们提到的不符,(tableSizeFor是将给定的初始容量转化为2的幂数的函数,他返回转化后的初始容量)。其实并不是这样,我们发现这个构造函数并没有初始化我们的table数组,因此在之后的resize函数中会对threshold重新赋值。
public HashMap(int initialCapacity
, float loadFactor
) {
if (initialCapacity
< 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity
);
if (initialCapacity
> MAXIMUM_CAPACITY
)
initialCapacity
= MAXIMUM_CAPACITY
;
if (loadFactor
<= 0 || Float
.isNaN(loadFactor
))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor
);
this.loadFactor
= loadFactor
;
this.threshold
= tableSizeFor(initialCapacity
);
}
static final int tableSizeFor(int cap
) {
int n
= cap
- 1;
n
|= n
>>> 1;
n
|= n
>>> 2;
n
|= n
>>> 4;
n
|= n
>>> 8;
n
|= n
>>> 16;
return (n
< 0) ? 1 : (n
>= MAXIMUM_CAPACITY
) ? MAXIMUM_CAPACITY
: n
+ 1;
}
public HashMap(int initialCapacity):通过给定的初始容量创建map,它会自动调用第一种构造函数public HashMap():创建一个空map
public HashMap() {
this.loadFactor
= DEFAULT_LOAD_FACTOR
;
}
public HashMap(Map<? extends K, ? extends V> m):通过给定的map创建一个新的map,我们查看这个putMapEntries函数
public HashMap(Map
<? extends K, ? extends V> m
) {
this.loadFactor
= DEFAULT_LOAD_FACTOR
;
putMapEntries(m
, false);
}
final void putMapEntries(Map
<? extends K, ? extends V> m
, boolean evict
) {
int s
= m
.size();
if (s
> 0) {
if (table
== null
) {
float ft
= ((float)s
/ loadFactor
) + 1.0F;
int t
= ((ft
< (float)MAXIMUM_CAPACITY
) ?
(int)ft
: MAXIMUM_CAPACITY
);
if (t
> threshold
)
threshold
= tableSizeFor(t
);
}
else if (s
> threshold
)
resize();
for (Map
.Entry
<? extends K, ? extends V> e
: m
.entrySet()) {
K key
= e
.getKey();
V value
= e
.getValue();
putVal(hash(key
), key
, value
, false, evict
);
}
}
}
4.其他方法介绍
size():返回map的sizeclear():清空mapclone():返回一个深拷贝mapisEmpty():根据size判断,map是否为空public V put(K key, V value):将给定的键值对存储在map中
public V
put(K key
, V value
) {
return putVal(hash(key
), key
, value
, false, true);
}
static final int hash(Object key
) {
int h
;
return (key
== null
) ? 0 : (h
= key
.hashCode()) ^ (h
>>> 16);
}
final V
putVal(int hash
, K key
, V value
, boolean onlyIfAbsent
,
boolean evict
) {
Node
<K,V>[] tab
; Node
<K,V> p
; int n
, i
;
if ((tab
= table
) == null
|| (n
= tab
.length
) == 0)
n
= (tab
= resize()).length
;
if ((p
= tab
[i
= (n
- 1) & hash
]) == null
)
tab
[i
] = newNode(hash
, key
, value
, null
);
else {
Node
<K,V> e
; K k
;
if (p
.hash
== hash
&&
((k
= p
.key
) == key
|| (key
!= null
&& key
.equals(k
))))
e
= p
;
else if (p
instanceof TreeNode)
e
= ((TreeNode
<K,V>)p
).putTreeVal(this, tab
, hash
, key
, value
);
else {
for (int binCount
= 0; ; ++binCount
) {
if ((e
= p
.next
) == null
) {
p
.next
= newNode(hash
, key
, value
, null
);
if (binCount
>= TREEIFY_THRESHOLD
- 1)
treeifyBin(tab
, hash
);
break;
}
if (e
.hash
== hash
&&
((k
= e
.key
) == key
|| (key
!= null
&& key
.equals(k
))))
break;
p
= e
;
}
}
if (e
!= null
) {
V oldValue
= e
.value
;
if (!onlyIfAbsent
|| oldValue
== null
)
e
.value
= value
;
afterNodeAccess(e
);
return oldValue
;
}
}
++modCount
;
if (++size
> threshold
)
resize();
afterNodeInsertion(evict
);
return null
;
}
public V get(Object key) : 返回给定键的值,如果给定键不存在则返回null
public V
get(Object key
) {
Node
<K,V> e
;
return (e
= getNode(hash(key
), key
)) == null
? null
: e
.value
;
}
final Node
<K,V> getNode(int hash
, Object key
) {
Node
<K,V>[] tab
; Node
<K,V> first
, e
; int n
; K k
;
if ((tab
= table
) != null
&& (n
= tab
.length
) > 0 &&
(first
= tab
[(n
- 1) & hash
]) != null
) {
if (first
.hash
== hash
&&
((k
= first
.key
) == key
|| (key
!= null
&& key
.equals(k
))))
return first
;
if ((e
= first
.next
) != null
) {
if (first
instanceof TreeNode)
return ((TreeNode
<K,V>)first
).getTreeNode(hash
, key
);
do {
if (e
.hash
== hash
&&
((k
= e
.key
) == key
|| (key
!= null
&& key
.equals(k
))))
return e
;
} while ((e
= e
.next
) != null
);
}
}
return null
;
}
containsKey(Object key):确定map中是否存在该key,返回布尔值,与get()方法的实现方法一致。
containsValue(Object value):与上一个方法类似。 public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction):尝试计算用于指定键和其当前映射的值的映射(或 null如果没有当前映射),如果映射得到的新value为null,则删除此键值对,若key不存在且新value值部位null,则插入该键值对。
public V
compute(K key
,
BiFunction
<? super K
, ? super V
, ? extends V> remappingFunction
) {
if (remappingFunction
== null
)
throw new NullPointerException();
int hash
= hash(key
);
Node
<K,V>[] tab
; Node
<K,V> first
; int n
, i
;
int binCount
= 0;
TreeNode
<K,V> t
= null
;
Node
<K,V> old
= null
;
if (size
> threshold
|| (tab
= table
) == null
||
(n
= tab
.length
) == 0)
n
= (tab
= resize()).length
;
if ((first
= tab
[i
= (n
- 1) & hash
]) != null
) {
if (first
instanceof TreeNode)
old
= (t
= (TreeNode
<K,V>)first
).getTreeNode(hash
, key
);
else {
Node
<K,V> e
= first
; K k
;
do {
if (e
.hash
== hash
&&
((k
= e
.key
) == key
|| (key
!= null
&& key
.equals(k
)))) {
old
= e
;
break;
}
++binCount
;
} while ((e
= e
.next
) != null
);
}
}
V oldValue
= (old
== null
) ? null
: old
.value
;
V v
= remappingFunction
.apply(key
, oldValue
);
if (old
!= null
) {
if (v
!= null
) {
old
.value
= v
;
afterNodeAccess(old
);
}
else
removeNode(hash
, key
, null
, false, true);
}
else if (v
!= null
) {
if (t
!= null
)
t
.putTreeVal(this, tab
, hash
, key
, v
);
else {
tab
[i
] = newNode(hash
, key
, v
, first
);
if (binCount
>= TREEIFY_THRESHOLD
- 1)
treeifyBin(tab
, hash
);
}
++modCount
;
++size
;
afterNodeInsertion(true);
}
return v
;
}
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction):与compute实现方法类似,但是如果指定key值存在,则函数映射不会进行计算,这某种程度上比 put() 性能更好public V computeIfPrsent(K key, Function<? super K, ? extends V> mappingFunction):与上述类似不在重复。V remove(Object key):移除指定的键值对。
public V
remove(Object key
) {
Node
<K,V> e
;
return (e
= removeNode(hash(key
), key
, null
, false, true)) == null
?
null
: e
.value
;
}
final Node
<K,V> removeNode(int hash
, Object key
, Object value
,
boolean matchValue
, boolean movable
) {
Node
<K,V>[] tab
; Node
<K,V> p
; int n
, index
;
if ((tab
= table
) != null
&& (n
= tab
.length
) > 0 &&
(p
= tab
[index
= (n
- 1) & hash
]) != null
) {
Node
<K,V> node
= null
, e
; K k
; V v
;
if (p
.hash
== hash
&&
((k
= p
.key
) == key
|| (key
!= null
&& key
.equals(k
))))
node
= p
;
else if ((e
= p
.next
) != null
) {
if (p
instanceof TreeNode)
node
= ((TreeNode
<K,V>)p
).getTreeNode(hash
, key
);
else {
do {
if (e
.hash
== hash
&&
((k
= e
.key
) == key
||
(key
!= null
&& key
.equals(k
)))) {
node
= e
;
break;
}
p
= e
;
} while ((e
= e
.next
) != null
);
}
}
if (node
!= null
&& (!matchValue
|| (v
= node
.value
) == value
||
(value
!= null
&& value
.equals(v
)))) {
if (node
instanceof TreeNode)
((TreeNode
<K,V>)node
).removeTreeNode(this, tab
, movable
);
else if (node
== p
)
tab
[index
] = node
.next
;
else
p
.next
= node
.next
;
++modCount
;
--size
;
afterNodeRemoval(node
);
return node
;
}
}
return null
;
}
resize(): 详情请看jdk1.8 HashMap源码分析(resize函数)
final Node
<K,V>[] resize() {
Node
<K,V>[] oldTab
= table
;
int oldCap
= (oldTab
== null
) ? 0 : oldTab
.length
;
int oldThr
= threshold
;
int newCap
, newThr
= 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;
}
else if (oldThr
> 0)
newCap
= oldThr
;
else {
newCap
= DEFAULT_INITIAL_CAPACITY
;
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"})
Node
<K,V>[] newTab
= (Node
<K,V>[])new Node[newCap
];
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 {
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
;
}
5.红黑树存储结构介绍
下文内容部分参考自: 【Java入门提高篇】Day25 史上最详细的HashMap红黑树解析
Java源码阅读笔记之TreeNode JDK8:HashMap源码解析:TreeNode类的moveRootToFront方法
红黑树的特点:
红黑树的根结点一定是黑色红色结点的子节点一定是黑色一个结点的左右子节点的颜色一定相同每个结点到其所有子节点的路径上黑色结点数一定相同
红黑树的插入规则:
1.如果插入的结点是根结点,则把颜色改为黑色即可2.如果插入的结点的父节点是黑色,则不操作3.如果插入结点的父节点和祖父节点都存在,且父节点为祖父节点的左节点,则分为两种情况讨论
如果叔父节点的颜色为红色,则将父节点和叔父节点的颜色改为黑色,祖父节点改为红色如果叔父节点的颜色为黑色或者叔父节点为null,则分两种情况讨论
如果 插入节点为父节点的左节点,将父节点改为黑色,祖父节点改为红色,祖父节点右旋如果插入节点为父节点的右节点,将父节点左旋 4.如果插入节点父节点和祖父节点都存在,且父节点为祖父节点的右节点,则分为两种情况
如果叔父节点的颜色为红色,则将父节点和叔父节点的颜色改为黑色,祖父节点改为红色如果叔父节点的颜色为黑色,或者叔父节点为null
如果插入节点为父节点的左节点,则将父节点右旋如果插入节点为父节点的右节点,则将父节点的颜色改为黑色,祖父节点的颜色改为红色,然后祖父节点左旋 直到到达情况1或者情况2终止。
红黑树结点的删除 – 三种情况:
被删除结点没有子结点,直接删除被删除结点有左节点或者右节点被删除结点同时有左节点和右节点,此时遵循二叉搜索树的删除方法,寻找被删除结点的后继结点,将key值对换,则问题转换为删除后继结点,当然后继结点是最多只有一个子节点的,那么就把问题转化为第二种情况了。之后请参考上面的博文!!![笔者画图太丑]
红黑树的查找效率:
O(n)
红黑树的删除效率:
O(n)
treeNode:注意为双向链表!继承自LinkedHashMap.Entry<K,V>
left:左节点right:右节点prev:链表中的上一个节点next:链表中的下一个节点parent:父节点red:红黑树的颜色 false为黑色,true为红色。
rotateLeft()/rorateRight():左转和右转,用于平衡红黑树。
treeify(Node<K,V>[] tab):void:将table中的结点转化为红黑树,注意链表转化为红黑树时,红黑树结点还是保存着next属性,既用于将链表转化为红黑树,有用于将红黑树转化为链表。
final void treeify(Node
<K,V>[] tab
) {
TreeNode
<K,V> root
= null
;
for (TreeNode
<K,V> x
= this, next
; x
!= null
; x
= next
) {
next
= (TreeNode
<K,V>)x
.next
;
x
.left
= x
.right
= null
;
if (root
== null
) {
x
.parent
= null
;
x
.red
= false;
root
= x
;
}
else {
K k
= x
.key
;
int h
= x
.hash
;
Class
<?> kc
= null
;
for (TreeNode
<K,V> p
= root
;;) {
int dir
, ph
;
K pk
= p
.key
;
if ((ph
= p
.hash
) > h
)
dir
= -1;
else if (ph
< h
)
dir
= 1;
else if ((kc
== null
&&
(kc
= comparableClassFor(k
)) == null
) ||
(dir
= compareComparables(kc
, k
, pk
)) == 0)
dir
= tieBreakOrder(k
, pk
);
TreeNode
<K,V> xp
= p
;
if ((p
= (dir
<= 0) ? p
.left
: p
.right
) == null
) {
x
.parent
= xp
;
if (dir
<= 0)
xp
.left
= x
;
else
xp
.right
= x
;
root
= balanceInsertion(root
, x
);
break;
}
}
}
}
moveRootToFront(tab
, root
);
}
Node<K,V> untreeify(HashMap<K,V> map):将table中的元素从红黑树转化为链表。
final Node
<K,V> untreeify(HashMap
<K,V> map
) {
Node
<K,V> hd
= null
, tl
= null
;
for (Node
<K,V> q
= this; q
!= null
; q
= q
.next
) {
Node
<K,V> p
= map
.replacementNode(q
, null
);
if (tl
== null
)
hd
= p
;
else
tl
.next
= p
;
tl
= p
;
}
return hd
;
}
TreeNode<K,V> root():返回红黑树的根结点,注意当链表转化为红黑树之后,红黑树的根结点并不一定是table数组中的元素,需要通过moveRootToFront()方法将root结点转化为table中的元素<K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root):
static <K,V> void moveRootToFront(Node
<K,V>[] tab
, TreeNode
<K,V> root
) {
int n
;
if (root
!= null
&& tab
!= null
&& (n
= tab
.length
) > 0) {
int index
= (n
- 1) & root
.hash
;
TreeNode
<K,V> first
= (TreeNode
<K,V>)tab
[index
];
if (root
!= first
) {
Node
<K,V> rn
;
tab
[index
] = root
;
TreeNode
<K,V> rp
= root
.prev
;
if ((rn
= root
.next
) != null
)
((TreeNode
<K,V>)rn
).prev
= rp
;
if (rp
!= null
)
rp
.next
= rn
;
if (first
!= null
)
first
.prev
= root
;
root
.next
= first
;
root
.prev
= null
;
}
assert checkInvariants(root
);
}
}
TreeNode<K,V> find(int h, Object k, Class<?> kc):用于寻找指定的结点并返回。
final TreeNode
<K,V> find(int h
, Object k
, Class
<?> kc
) {
TreeNode
<K,V> p
= this;
do {
int ph
, dir
; K pk
;
TreeNode
<K,V> pl
= p
.left
, pr
= p
.right
, q
;
if ((ph
= p
.hash
) > h
)
p
= pl
;
else if (ph
< h
)
p
= pr
;
else if ((pk
= p
.key
) == k
|| (k
!= null
&& k
.equals(pk
)))
return p
;
else if (pl
== null
)
p
= pr
;
else if (pr
== null
)
p
= pl
;
else if ((kc
!= null
||
(kc
= comparableClassFor(k
)) != null
) &&
(dir
= compareComparables(kc
, k
, pk
)) != 0)
p
= (dir
< 0) ? pl
: pr
;
else if ((q
= pr
.find(h
, k
, kc
)) != null
)
return q
;
else
p
= pl
;
} while (p
!= null
);
return null
;
}
TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,int h, K k, V v):将指定的结点插入到红黑树中,在阅读源码之前建议先查看之前给出的将结点插入到红黑树中的几种case和方法。
final TreeNode
<K,V> putTreeVal(HashMap
<K,V> map
, Node
<K,V>[] tab
,
int h
, K k
, V v
) {
Class
<?> kc
= null
;
boolean searched
= false;
TreeNode
<K,V> root
= (parent
!= null
) ? root() : this;
for (TreeNode
<K,V> p
= root
;;) {
int dir
, ph
; K pk
;
if ((ph
= p
.hash
) > h
)
dir
= -1;
else if (ph
< h
)
dir
= 1;
else if ((pk
= p
.key
) == k
|| (k
!= null
&& k
.equals(pk
)))
return p
;
else if ((kc
== null
&&
(kc
= comparableClassFor(k
)) == null
) ||
(dir
= compareComparables(kc
, k
, pk
)) == 0) {
if (!searched
) {
TreeNode
<K,V> q
, ch
;
searched
= true;
if (((ch
= p
.left
) != null
&&
(q
= ch
.find(h
, k
, kc
)) != null
) ||
((ch
= p
.right
) != null
&&
(q
= ch
.find(h
, k
, kc
)) != null
))
return q
;
}
dir
= tieBreakOrder(k
, pk
);
}
TreeNode
<K,V> xp
= p
;
if ((p
= (dir
<= 0) ? p
.left
: p
.right
) == null
) {
Node
<K,V> xpn
= xp
.next
;
TreeNode
<K,V> x
= map
.newTreeNode(h
, k
, v
, xpn
);
if (dir
<= 0)
xp
.left
= x
;
else
xp
.right
= x
;
xp
.next
= x
;
x
.parent
= x
.prev
= xp
;
if (xpn
!= null
)
((TreeNode
<K,V>)xpn
).prev
= x
;
moveRootToFront(tab
, balanceInsertion(root
, x
));
return null
;
}
}
}
balanceInsertion():参考文前给出的连接balanceDeletion():参考文前给出的链接,红黑树的删除平衡操作过于复杂,笔者参考了许多博客,对自己的见解也没有很大把握,就不在这里献丑了。void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,boolean movable):删除指定的节点,建议翻看前文给出的红黑树删除的逻辑方法。
final void removeTreeNode(HashMap
<K,V> map
, Node
<K,V>[] tab
,
boolean movable
) {
int n
;
if (tab
== null
|| (n
= tab
.length
) == 0)
return;
int index
= (n
- 1) & hash
;
TreeNode
<K,V> first
= (TreeNode
<K,V>)tab
[index
], root
= first
, rl
;
TreeNode
<K,V> succ
= (TreeNode
<K,V>)next
, pred
= prev
;
if (pred
== null
)
tab
[index
] = first
= succ
;
else
pred
.next
= succ
;
if (succ
!= null
)
succ
.prev
= pred
;
if (first
== null
)
return;
if (root
.parent
!= null
)
root
= root
.root();
if (root
== null
|| root
.right
== null
||
(rl
= root
.left
) == null
|| rl
.left
== null
) {
tab
[index
] = first
.untreeify(map
);
return;
}
TreeNode
<K,V> p
= this, pl
= left
, pr
= right
, replacement
;
if (pl
!= null
&& pr
!= null
) {
TreeNode
<K,V> s
= pr
, sl
;
while ((sl
= s
.left
) != null
)
s
= sl
;
boolean c
= s
.red
; s
.red
= p
.red
; p
.red
= c
;
TreeNode
<K,V> sr
= s
.right
;
TreeNode
<K,V> pp
= p
.parent
;
if (s
== pr
) {
p
.parent
= s
;
s
.right
= p
;
}
else {
TreeNode
<K,V> sp
= s
.parent
;
if ((p
.parent
= sp
) != null
) {
if (s
== sp
.left
)
sp
.left
= p
;
else
sp
.right
= p
;
}
if ((s
.right
= pr
) != null
)
pr
.parent
= s
;
}
p
.left
= null
;
if ((p
.right
= sr
) != null
)
sr
.parent
= p
;
if ((s
.left
= pl
) != null
)
pl
.parent
= s
;
if ((s
.parent
= pp
) == null
)
root
= s
;
else if (p
== pp
.left
)
pp
.left
= s
;
else
pp
.right
= s
;
if (sr
!= null
)
replacement
= sr
;
else
replacement
= p
;
}
else if (pl
!= null
)
replacement
= pl
;
else if (pr
!= null
)
replacement
= pr
;
else
replacement
= p
;
if (replacement
!= p
) {
TreeNode
<K,V> pp
= replacement
.parent
= p
.parent
;
if (pp
== null
)
root
= replacement
;
else if (p
== pp
.left
)
pp
.left
= replacement
;
else
pp
.right
= replacement
;
p
.left
= p
.right
= p
.parent
= null
;
}
TreeNode
<K,V> r
= p
.red
? root
: balanceDeletion(root
, replacement
);
if (replacement
== p
) {
TreeNode
<K,V> pp
= p
.parent
;
p
.parent
= null
;
if (pp
!= null
) {
if (p
== pp
.left
)
pp
.left
= null
;
else if (p
== pp
.right
)
pp
.right
= null
;
}
}
if (movable
)
moveRootToFront(tab
, r
);
}