红黑树:
基于BST(平衡二叉树)产生
旋转操作: 保持高度在logN
- 每个节点或是红色,或是黑色
- 根节点是黑色
- 每个叶子节点是黑色
- 如果一个节点是红色,那么他的两个子节点都是黑的
对每个节点,从该节点到其个叶子节点的所有路径上包含相同数目的黑节点
就是父子节点之间不能出现两个连续的红节点
查找复杂度:logN
插入数据:
- 新节点赋为红色,如果未黑色,会导致根到叶子路径上有一条路上,多一个额外黑色节点
- 设要插入的节点未N 父为 P ,
处理方式一
新结点N的叔叔结点U是红色的
处理: 只是变色
新节点N 叔叔节点是黑色,N 是左子
处理方式,对祖父节点右旋
这时会修改父指针的指向

N s是右子
先选择父, 在右旋根
数据机构
数组+ 单项链表 + 红黑树 
节点较少是:数组+ 单向链表
节点较多是 大于8 : 数组 +红黑树
基本属性
/*** 默认容量*/static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16/*** 最大容量*/static final int MAXIMUM_CAPACITY = 1 << 30;/*** 负载因子*/static final float DEFAULT_LOAD_FACTOR = 0.75f;/**转向红黑树的阈值*/static final int TREEIFY_THRESHOLD = 8;/*** 红黑树转链表的阈值*/static final int UNTREEIFY_THRESHOLD = 6;/*** 转红黑树时,table最小长度*/static final int MIN_TREEIFY_CAPACITY = 64;
1.7死循环的问题:
1.7会造成循环链表
1.8 采用尾插法,避免死循环
HashMap红黑树插入操作
static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,TreeNode<K,V> x) {// 新节点默认为红色x.red = true;// xp表示x的父结点,xpp表示x的祖父结点,xppl表示xpp的左孩子结点,xppr表示xpp的右孩子结点for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {// 如果x没有父结点,则表示x是第一个结点,自动为根节点,根节点为黑色if ((xp = x.parent) == null) {x.red = false;return x;}// 如果父结点不是红色(就是黑色),或者x没有祖父节点,那么就证明x是第二层节点,父节点为根节点// 这种情况无需就行操作else if (!xp.red || (xpp = xp.parent) == null)return root;// 进入到这里,表示x的父节点为红色// 如果x的父节点是祖父结点的左孩子if (xp == (xppl = xpp.left)) {// 祖父结点的右孩子,也就是x的叔叔节点不为空,且为红色if ((xppr = xpp.right) != null && xppr.red) {// 父节点和叔叔节点都为红色,只需要变色,且将x替换为祖父节点然后进行递归xppr.red = false;xp.red = false;xpp.red = true;x = xpp;}// 如果叔叔节点为空,或者为黑色else {// 如果x节点为xp的右孩子if (x == xp.right) {// 先进行左旋,并且把x替换为xp进行递归,在左旋的过程中产生了新的root节点root = rotateLeft(root, x = xp);// x替换后,修改xp和xppxpp = (xp = x.parent) == null ? null : xp.parent;}// 如果x本来是左孩子,或者已经经过了上面的左旋之后,进行变色加右旋if (xp != null) {xp.red = false;if (xpp != null) {xpp.red = true;root = rotateRight(root, xpp);}}}}// 如果x的父节点是祖父结点的右孩子else {if (xppl != null && xppl.red) {xppl.red = false;xp.red = false;xpp.red = true;x = xpp;}else {if (x == xp.left) {root = rotateRight(root, x = xp);xpp = (xp = x.parent) == null ? null : xp.parent;}if (xp != null) {xp.red = false;if (xpp != null) {xpp.red = true;root = rotateLeft(root, xpp);}}}}}}
红黑树的左右选操作
static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,TreeNode<K,V> p) {// pp是祖父结点// p是待旋转结点// r是p的右孩子结点// rl是r的左孩子结点TreeNode<K,V> r, pp, rl;if (p != null && (r = p.right) != null) {// 如果rl不为空,则设置p.right=rlif ((rl = p.right = r.left) != null)rl.parent = p;// 如果祖父结点为null,那么r设置为黑色,r左旋之后即为root节点if ((pp = r.parent = p.parent) == null)(root = r).red = false;// 如果待旋转结点是左孩子节点else if (pp.left == p)pp.left = r;// 如果待旋转结点为右孩子elsepp.right = r;r.left = p;p.parent = r;}return root;}static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,TreeNode<K,V> p) {TreeNode<K,V> l, pp, lr;if (p != null && (l = p.left) != null) {if ((lr = p.left = l.right) != null)lr.parent = p;if ((pp = l.parent = p.parent) == null)(root = l).red = false;else if (pp.right == p)pp.right = l;elsepp.left = l;l.right = p;p.parent = l;}return root;}
HashMap的树话
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;// 判断待插入结点应该插入在左子树还是右子树// 先比较hash值if ((ph = p.hash) > h)dir = -1;else if (ph < h)dir = 1;// 如果hash值相等,然后比较k.compareTo(pk)else if ((kc == null &&(kc = comparableClassFor(k)) == null) ||(dir = compareComparables(kc, k, pk)) == 0)// 如果还相等则再比较identityHashCodedir = tieBreakOrder(k, pk);// 根据dir的值就知道了待插入结点该插在左子树还是右子树了TreeNode<K,V> xp = p;if ((p = (dir <= 0) ? p.left : p.right) == null) {x.parent = xp;if (dir <= 0)xp.left = x;elsexp.right = x;root = balanceInsertion(root, x);break;}}}}moveRootToFront(tab, root);}
PUT的过程
- 生成hashCode
- 判断数组是否为空,初始化数组
- 根据hashCode算出数组下表
- 判断当前数组元素是否为空
如果为空:封装node 对象
如果不为空:
如果当前类型是是treeNode, 就是红黑树,把key value插入红黑树中
如果不是treeNode类型,就是链表
链表方式查找,封装node插入尾部,
判断个数是不是大于8,如果是转成红黑树
5:. modeCount ++
6。 HashMap元素size +1
7:判断是否扩容
get的过程
- 根据key生成hashCode
- 如果数组为空,直接返回
- 计算数组下表
- 当前数组是否为空,空直接返回
- 判断该数组第一个位置上的key是否相同
- 如果不等,还没有下个节点就返回
- 有下个节点判断是链表,还是红黑树
- 遍历链表
- 遍历红黑树
- 找到返回
