1、TreeNode静态方法:验证红黑树的准确性,checkInvariants(该方法需要在启动参数中加 -ae 才能生效)
/**
* 验证红黑树的准确性
*
* @param t 数据验证的起始根节点
* @return boolean
* @Author muyi
* @Date 17:53 2020/7/30
*/
static <K, V> boolean checkInvariants(HashMap.TreeNode<K, V> t) {
// tp-父节点,tl-左子节点,tr-右子节点,tp-前驱节点,tn-后继节点
HashMap.TreeNode<K, V> tp = t.parent, tl = t.left, tr = t.right,
tb = t.prev, tn = (HashMap.TreeNode<K, V>) t.next;
// 当出现以下任一情况时,红黑树或者双向链表不正确
// 1、如果前驱节点存在,但是前驱节点的后继节点不是当前节点
if (tb != null && tb.next != t)
return false;
// 2、如果后继节点存在,但是后继节点的前驱节点不是当前节点
if (tn != null && tn.prev != t)
return false;
// 3、父节点存在,但是父节点的左子节点、右子节点均不是当前节点
if (tp != null && t != tp.left && t != tp.right)
return false;
// 4、左子节点存在。但是左子节点的父节点不是当前节点或者左子节点的hash值大于当前节点的hash值
if (tl != null && (tl.parent != t || tl.hash > t.hash))
return false;
// 5、右子节点存在。但是右子节点的父节点不是当前节点或者右子节点的hash值小于当前节点的hash值
if (tr != null && (tr.parent != t || tr.hash < t.hash))
return false;
// 6、当前节点是红色,孩子节点也是红色
if (t.red && tl != null && tl.red && tr != null && tr.red)
return false;
// 递归验证左子树
if (tl != null && !checkInvariants(tl))
return false;
// 递归验证右子树
if (tr != null && !checkInvariants(tr))
return false;
// 都正确返回true
return true;
}
2、TreeNode静态方法:将红黑树的root节点移动到tab相对应的索引位置,moveRootToFront
/**
* 将红黑树的root节点移动到tab相对应的索引位置
* 在树化的过程中,所有的节点的prev、next值均未改变,这里可以简单的理解为对双向链表进行维护
*
* @param tab 数组表
* @param root 红黑树的根节点
* @return void
* @Author muyi
* @Date 17:25 2020/7/30
*/
static <K, V> void moveRootToFront(HashMap.Node<K, V>[] tab, HashMap.TreeNode<K, V> root) {
int n;
if (root != null && tab != null && (n = tab.length) > 0) {
// 计算索引
int index = (n - 1) & root.hash;
// 原链表的头节点
HashMap.TreeNode<K, V> first = (HashMap.TreeNode<K, V>) tab[index];
// 如果头节点和红黑树的root节点不相等,就需要找到root节点在链表中位置,并在链表中进行数据交换
if (root != first) {
// 后继节点
HashMap.Node<K, V> rn;
tab[index] = root;
// root的前驱节点
HashMap.TreeNode<K, V> rp = root.prev;
// 如果root的后继节点存在,则将它的前驱节点指向root的前驱节点
if ((rn = root.next) != null)
((HashMap.TreeNode<K, V>) rn).prev = rp;
// 如果root的前驱节点存在,则将它的后继节点指向root的后继节点
if (rp != null)
rp.next = rn;
// 链表中的头节点存在,则将他的前驱节点指向root
if (first != null)
first.prev = root;
// root的后继节点指向头节点
root.next = first;
// root的前驱节点指向null
root.prev = null;
}
// 递归不变检查(验证红黑树的正确性)
assert checkInvariants(root);
}
}