再接上篇,HashMap的最后一部分源码
主要是TreeNode逻辑实现,其中包含红黑树增删的相关算法(具体可以参考红黑树的相关介绍)
/** * TreeNode的Entry类 * * TreeNode维持为红黑树,保证树的高度为O(logN),并按hashCode有序 */ static final class TreeNode<K, V> extends LinkedHashMap.Entry<K, V> { TreeNode<K, V> parent; // 父节点 TreeNode<K, V> left; // 左子树 TreeNode<K, V> right; // 右子树 TreeNode<K, V> prev; // 链接的下个节点,用于删除 boolean red; // 红黑标志 TreeNode(int hash, K key, V val, Node<K, V> next) { super(hash, key, val, next); } // TreeNode内部使用/////////////////////// /** * 回溯获取根节点 */ final TreeNode<K, V> root() { for (TreeNode<K, V> r = this, p;;) { if ((p = r.parent) == null) return r; r = p; } } /** * 将根节点移到桶的首元素(也就是放到tab数组里),静态方法 * * 删除根节点的时候可能新的根节点不是首元素 */ 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); // Tree结构没有改变 } } /** * 递归寻找key==k的节点 * * @param kc (上层)缓存的comparableClassFor(key)的返回值 */ 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; // 如果hashCode不同,先根据hashCode定位子树 // XXX 同一桶内会发生么? if ((ph = p.hash) > h) p = pl; else if (ph < h) p = pr; // 以下为ph == h else if ((pk = p.key) == k || (k != null && k.equals(pk))) return p; // equal,找到返回 // 只有<=1棵子树情况 else if (pl == null) p = pr; else if (pr == null) p = pl; // 有两棵子树,且是Comparable,则根据Comparable判断 else if ((kc != null || (kc = comparableClassFor(k)) != null) && (dir = compareComparables(kc, k, pk)) != 0) p = (dir < 0) ? pl : pr; // 有两棵子树,但不是Comparable,这时只能去两个子树一起找(O(N)) // 这地方循环和递归各处理一个子树 else if ((q = pr.find(h, k, kc)) != null) return q; else p = pl; } while (p != null); return null; } /** * 辅助方法用来给两个对象指定顺序 * * 用于处理hashCode相同又不是Comparable的情况 */ static int tieBreakOrder(Object a, Object b) { int d; if (a == null || b == null // 如果不是同一个类,就根据类名排序 || (d = a.getClass().getName().compareTo(b.getClass().getName())) == 0) // 否则就根据原生(未重写)的hashCode来排序,System.identityHashCode是native实现 d = (System.identityHashCode(a) <= System.identityHashCode(b) ? -1 : 1); return d; } // HashMap使用////////////////////// /** * 在当前节点所在的整个树(就是这个桶)里寻找key.equals(k)的节点 */ final TreeNode<K, V> getTreeNode(int h, Object k) { return ((parent != null) ? root() : this).find(h, k, null); } /** * 将本节点所属的桶转化为树状结构(调用时该桶应为TreeNode组成的列表) * * @return 根节点 */ 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;;) { // 内层向当前成树的部分插入节点x(满足排序关系) int dir, ph; // dir是排序对比结果,ph是p的hash值 K pk = p.key; if ((ph = p.hash) > h) {// 比较p和x的顺序 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; // 缓存p if ((p = (dir <= 0) ? p.left : p.right) == null) { // 如果找到了空位,就把x放进去,否则在对应子树继续循环找 x.parent = xp; if (dir <= 0) { xp.left = x; } else { xp.right = x; } // 平衡当前的树,保持红黑树特性 root = balanceInsertion(root, x); break; } } } } moveRootToFront(tab, root); // 根节点挪到桶的第一个(链结构中) } /** * 将本节点所在桶退化为普通的链表桶 * * @param map 只是为了引用辅助的实体方法 */ final Node<K, V> untreeify(HashMap<K, V> map) { Node<K, V> hd = null, tl = null; // 遍历每个节点(TreeNode),转为普通节点然后串成链表 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桶的put实现 * * @return 如果k存在,返回对应的(旧)节点,注意此方法不执行value覆盖(由外层根据具体情况判断是否覆盖) * * 如果k不存在,返回null */ 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;;) { // 逐层寻找put的位置 int dir, ph; K pk; // 比较hash值 if ((ph = p.hash) > h) { dir = -1; } else if (ph < h) { dir = 1; } else if ((pk = p.key) == k || (pk != null && k.equals(pk))) return p; // 找到equal,直接返回了 else if ((kc == null && (kc = comparableClassFor(k)) == null) || (dir = compareComparables(kc, k, pk)) == 0) { // 根据Comparable比较不出的话,只能遍历整个子树来判断Equal if (!searched) { TreeNode<K, V> q, ch; searched = true; // 在子树递归寻找equal,这个分支由searched标志,只会执行一次 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; } // 这里就是真没有Equal的,又没办法比较出来,只能规定顺序来使循环继续 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; } // 插入链表(注意TreeNode桶仍然维护链表结构) xp.next = x; x.parent = x.prev = xp; // 挂在prev节点下作为子节点 if (xpn != null) { ((TreeNode<K, V>) xpn).prev = x; } // 根节点移动桶首位 moveRootToFront(tab, balanceInsertion(root, x)); return null; } } } /** * TreeNode桶中删除本节点(this) This is messier than typical red-black deletion code because we * cannot swap the contents of an interior node with a leaf successor that is pinned by * "next" pointers that are accessible independently during traversal. So instead we swap * the tree linkages. XXX */ 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; // 本节点在链结构里的前后节点 // 先在链结构中删除this if (pred == null) { // 如果this是首节点,则原桶中次节点递补 tab[index] = first = succ; } else { pred.next = succ; } if (succ != null) { succ.prev = pred; } if (first == null) { // 如果桶已经删空了,那么没什么别的要做的了 return; } // 找到(原)树结构中的根(树结构中还没删this,一般情况下应不会进这个if) if (root.parent != null) { root = root.root(); } // 树太小的情况(顶部三层中有null,注意红黑树是准平衡的),直接不要树结构了,退化为链表 if (root == null || root.right == null || (rl = root.left) == null || rl.left == null) { tab[index] = first.untreeify(map); // too small return; } // 这里开始真正在树结构里删,比较复杂,参见红黑树的删除过程 // TODO TreeNode<K, V> p = this, pl = left, pr = right, replacement; // this,左右子树,替代节点 // 以下为寻找replacement过程,replacement至少有一个子树为null if (pl != null && pr != null) { // 左右子树均非空 TreeNode<K, V> s = pr, sl; // 右节点(sister) while ((sl = s.left) != null) { // 右子树里面最左侧的叶节点(successor) s = sl; } // 交换this和successor的颜色 boolean c = s.red; s.red = p.red; p.red = c; TreeNode<K, V> sr = s.right; // successor的右节点 TreeNode<K, V> pp = p.parent; // this的父节点 if (s == pr) { // successor就是p的(直接)右节点(说明s没有左子树) // 交换this和s的位置 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) { // detach 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); } } /** * TreeNode桶切分,用于resize。如切分后树过小,则退化为链表 * * @param map the map * @param tab the table for recording bin heads * @param index 待切分的桶下标 * @param bit 旧hash掩码(旧capacity) */ final void split(HashMap<K, V> map, Node<K, V>[] tab, int index, int bit) { TreeNode<K, V> b = this; // 本节点 // 分离后高低位桶的链结构 TreeNode<K, V> loHead = null, loTail = null; TreeNode<K, V> hiHead = null, hiTail = null; int lc = 0, hc = 0; // 新桶的尺寸 // 建立新的链结构 for (TreeNode<K, V> e = b, next; e != null; e = next) { // 遍历旧桶元素 next = (TreeNode<K, V>) e.next; e.next = null; if ((e.hash & bit) == 0) { // 低位桶 if ((e.prev = loTail) == null) { loHead = e; } else { loTail.next = e; } loTail = e; ++lc; } else { // 高位桶 if ((e.prev = hiTail) == null) { hiHead = e; } else { hiTail.next = e; } hiTail = e; ++hc; } } // 如节点数过少则退化为链表,否则重新组织两个桶成树 if (loHead != null) { if (lc <= UNTREEIFY_THRESHOLD) { tab[index] = loHead.untreeify(map); } else { tab[index] = loHead; if (hiHead != null) // (else is already treeified) loHead.treeify(tab); } } if (hiHead != null) { if (hc <= UNTREEIFY_THRESHOLD) { tab[index + bit] = hiHead.untreeify(map); } else { tab[index + bit] = hiHead; if (loHead != null) hiHead.treeify(tab); } } } // 红黑树相关操作静态方法 /////////////////// // 参考http://blog.chinaunix.net/uid-26575352-id-3061918.html /** * 左旋-节点p向左下降一层,原右节点代替节点p * * @param root * @param p 操作节点 * @return */ static <K, V> TreeNode<K, V> rotateLeft(TreeNode<K, V> root, TreeNode<K, V> p) { TreeNode<K, V> r, pp, rl; // 右,父,右左 if (p != null && (r = p.right) != null) { // 没有右子的话不操作 if ((rl = p.right = r.left) != null) { rl.parent = p; // 右左节点变为p的右节点,代替r的位置 } // 原r节点移到p的位置 if ((pp = r.parent = p.parent) == null) { (root = r).red = false; // 如果p原先是根节点,则原r成为新根节点 } else if (pp.left == p) { pp.left = r; } else { pp.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; else pp.left = l; l.right = p; p.parent = l; } return root; } /** * 平衡插入操作,调用本方法时x节点已插入,本方法调整树结构来维持红黑树特性 * * @param root * @param x 新插入的节点,且为红色叶节点 * @return */ static <K, V> TreeNode<K, V> balanceInsertion(TreeNode<K, V> root, TreeNode<K, V> x) { x.red = true; for (TreeNode<K, V> xp, xpp, xppl, xppr;;) { // 父,祖父,祖父的左右子节点 if ((xp = x.parent) == null) { // 1.如果x是根,说明原来是空树,改成黑色就行了 x.red = false; return x; } else if (!xp.red || (xpp = xp.parent) == null) { // 2.父节点是黑色,则红黑树性质没有破坏(注意x是红的),不需要任何操作 return root; } // xp是红色,此时xp违反红黑树特性 if (xp == (xppl = xpp.left)) { // xp是左节点 if ((xppr = xpp.right) != null && xppr.red) { // 3.xppr(叔父节点)是红色:将父、叔父改黑,祖父改红 // 此时父节点子树已经符合红黑树标准,问题转嫁到xpp上,继续循环 xppr.red = false; xp.red = false; xpp.red = true; x = xpp; } else { if (x == xp.right) { // 4.叔父是黑色,当前节点是右节点,则对xp左旋 // 此时问题转嫁到原xpl(兄弟)节点,归为情况5 root = rotateLeft(root, x = xp); xpp = (xp = x.parent) == null ? null : xp.parent; } // 5.叔父是黑色,当前节点是左节点 // 父节点改黑,祖父改红,并对祖父右旋 if (xp != null) { xp.red = false; if (xpp != null) { xpp.red = true; root = rotateRight(root, xpp); } } } } else { // xp是右节点,对称操作 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); } } } } } } /** * 平衡删除操作 * * @param root * @param x 被删除节点 * @return */ static <K, V> TreeNode<K, V> balanceDeletion(TreeNode<K, V> root, TreeNode<K, V> x) { for (TreeNode<K, V> xp, xpl, xpr;;) { if (x == null || x == root) return root; else if ((xp = x.parent) == null) { x.red = false; return x; } else if (x.red) { x.red = false; return root; } else if ((xpl = xp.left) == x) { if ((xpr = xp.right) != null && xpr.red) { xpr.red = false; xp.red = true; root = rotateLeft(root, xp); xpr = (xp = x.parent) == null ? null : xp.right; } if (xpr == null) x = xp; else { TreeNode<K, V> sl = xpr.left, sr = xpr.right; if ((sr == null || !sr.red) && (sl == null || !sl.red)) { xpr.red = true; x = xp; } else { if (sr == null || !sr.red) { if (sl != null) sl.red = false; xpr.red = true; root = rotateRight(root, xpr); xpr = (xp = x.parent) == null ? null : xp.right; } if (xpr != null) { xpr.red = (xp == null) ? false : xp.red; if ((sr = xpr.right) != null) sr.red = false; } if (xp != null) { xp.red = false; root = rotateLeft(root, xp); } x = root; } } } else { // symmetric if (xpl != null && xpl.red) { xpl.red = false; xp.red = true; root = rotateRight(root, xp); xpl = (xp = x.parent) == null ? null : xp.left; } if (xpl == null) x = xp; else { TreeNode<K, V> sl = xpl.left, sr = xpl.right; if ((sl == null || !sl.red) && (sr == null || !sr.red)) { xpl.red = true; x = xp; } else { if (sl == null || !sl.red) { if (sr != null) sr.red = false; xpl.red = true; root = rotateLeft(root, xpl); xpl = (xp = x.parent) == null ? null : xp.left; } if (xpl != null) { xpl.red = (xp == null) ? false : xp.red; if ((sl = xpl.left) != null) sl.red = false; } if (xp != null) { xp.red = false; root = rotateRight(root, xp); } x = root; } } } } } /** * 递归校验指针兼容性和整个树的有序性,容错机制 */ static <K, V> boolean checkInvariants(TreeNode<K, V> t) { TreeNode<K, V> tp = t.parent, tl = t.left, tr = t.right, tb = t.prev, tn = (TreeNode<K, V>) t.next; if (tb != null && tb.next != t) // prev.next=self return false; if (tn != null && tn.prev != t) // next.prev=self return false; if (tp != null && t != tp.left && t != tp.right) // self in (parent.left,parent.right) return false; if (tl != null && (tl.parent != t || tl.hash > t.hash)) // left.parent=self return false; if (tr != null && (tr.parent != t || tr.hash < t.hash)) // right.parent=self return false; if (t.red && tl != null && tl.red && tr != null && tr.red) // 红节点的子节点为黑(XXX 似乎应该有个是OR?) return false; // 递归 if (tl != null && !checkInvariants(tl)) return false; if (tr != null && !checkInvariants(tr)) return false; return true; } }
相关推荐
该项目为基于Java并发编程的ConcurrentHashMap测试设计源码,共包含24个文件,其中Java源文件21个,Git忽略文件1个,Markdown文档1个,XML配置文件1个。内容涵盖并发编程课件代码,适合学习并发编程相关知识。关注...
3. **数据结构与算法**:为了存储和操作通讯录中的联系人信息,项目可能使用了数据结构,如ArrayList或HashMap。这些数据结构的选择和使用直接影响到程序的性能和功能。 4. **文件I/O操作**:为了保存和加载通讯录...
在这个主题中,我们将深入探讨HashMap类,它是Java集合框架中的一个关键组件,特别是在标题“20-集合框架020-HashMap-1080P 高清-AVC20”和描述中所提到的内容。 HashMap是Java.util包中的一个类,它实现了Map接口...
【Java毕业设计项目源码——蓝宇快递打印系统】是一个基于Java编程语言的软件开发实践,主要用于实现快递公司的打印管理功能。这个系统包含了完整的源代码,对于学习Java编程,特别是针对毕业设计的学生来说,是一个...
2. **集合框架**:Java集合框架包含ArrayList、LinkedList、HashMap等数据结构,方便存储和管理对象。 3. **多线程**:Java.util.concurrent包提供了高级的线程管理和并发工具,如ExecutorService和Semaphore。 4. *...
hashmap源码 Excellent-Blog-share Welcome to share excellent blogs . 当你的能力还驾驭不了你的目标时,就应该沉下心来历练 当你的才华还撑不起你的野心时,那你就应该静下心来学习 #目录 ###附录 java系列 java8...
3. **Java集合框架**:在处理账户、交易等数据时,Java集合框架如ArrayList、LinkedList、HashMap等将起到关键作用。这些数据结构有助于有效地存储和操作数据。 4. **多线程**:由于银行应用通常涉及并发操作,如多...
在这个“java源码整理包-集合”中,包含了多种核心的集合类的源代码,如`List`、`Map`、`ArrayList`、`HashMap`、`HashSet`、`Hashtable`、`TreeMap`、`TreeSet`和`Vector`。这些源码对于深入理解Java集合的工作原理...
Java集合专题总结:HashMap和HashTable源码学习和面试总结 本文总结了Java集合专题中的HashMap和HashTable,涵盖了它们的源码学习和面试总结。HashMap是一种基于哈希表的集合类,它的存储结构是一个数组,每个元素...
这个Java源码实例对于学习Java网络编程、多线程、GUI设计以及P2P技术具有很高的参考价值。开发者可以通过阅读和理解代码,进一步掌握这些核心概念,并能在此基础上扩展出更多功能,比如文件共享、群聊、语音/视频...
在Java编程语言中,集合框架是开发者日常工作中不可或缺的一部分,HashMap作为其中的重要成员,它的实现原理对于理解Java性能优化和数据结构有深远的意义。HashMap是一个基于哈希表的数据结构,它实现了Map接口,...
**JAVA实战项目源码-计算机毕业设计java专业-项目源码-项目说明介绍-JAVA+SQL离散数学题库管理系统** 这个项目是一个基于JAVA编程语言和SQL数据库技术的离散数学题库管理系统,专为计算机专业学生设计,适用于毕业...
Java源码和Android 17源码是两个重要的学习资源,对于深入理解Java编程语言以及Android应用程序开发至关重要。这两部分源代码提供了丰富的信息,帮助开发者探究底层实现细节,提升编程技能,解决实际问题。 首先,...
在本资源包“三套Java基础课件加源码--晋级版”中,你将找到一系列精心设计的Java学习资料,旨在帮助初学者逐步提升技能并深入理解Java编程语言。这个资源包对于那些希望从基础知识开始,逐步进阶的开发者来说是理想...
Java JDK源码学习是深入理解Java编程语言的关键步骤,它能帮助开发者洞悉语言底层的工作原理,提升编程技能和优化代码的能力。JDK(Java Development Kit)是Java开发的核心工具集,包含了Java运行时环境(JRE)、...
《JAVA实战项目源码-家庭理财系统》是一个典型的JAVA编程语言实现的计算机毕业设计项目,旨在帮助学生理解和应用JAVA技术解决实际问题。该项目利用JAVA的强大力量,结合APPLET技术,构建了一个全面的家庭财务管理...
HashMap是Java编程语言中最常用的集合类之一,它提供了一种基于键值对(key-value pair)的数据存储方式,具有高效查找、插入和删除操作。在Java 8中,HashMap的实现有了很多改进,以提高性能和空间利用率。下面我们...
《Java开发-----图书管管理系统(视频+源码).rar》是一个综合的学习资源,它涵盖了Java编程语言在实际项目中的应用,特别关注于开发一个图书管理系统的全过程。这个压缩包包含了视频教程和完整的源代码,旨在帮助学习...
在Java编程语言中,了解和研究常用类的源码对于提升编程技能至关重要。Java的类库丰富多样,包含了大量预定义的类,这些类提供了许多基础功能,方便开发者快速构建应用程序。本文将深入探讨几个Java中常用的类,包括...
hashmap源码 learning-record - 学习轨迹记录 10月1号 7月18号 基础算法:反转单向链表 7月16号 7月11号 7月9号 复习 : HashTable和HashMap的区别详解 LeetCode 27. 删除元素(Remove Element) 7月8号 7月5号 复习...