1. //对treeMap的红黑树理解注解. 2017.02.16 by 何锦彬 JDK,1.7.51
  2.  
  3. /** From CLR */
  4. private void fixAfterInsertion(Entry<K, V> x) {
  5.  
  6. //新加入红黑树的默认节点就是红色
  7. x.color = RED;
  8. /**
  9. * 1. 如为根节点直接跳出
  10. */
  11. while (x != null && x != root && x.parent.color == RED) {
  12.  
  13. if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
  14.  
  15. //如果X的父节点(P)是其父节点的父节点(G)的左节点
  16. //即 下面这种情况
  17. /**
  18. * G
  19. * P(RED) U
  20. */
  21. //获取其叔(U)节点
  22. Entry<K, V> y = rightOf(parentOf(parentOf(x)));
  23. if (colorOf(y) == RED) {
  24. // 这种情况
  25. /**
  26. * G
  27. * P(RED) U(RED)
  28. * X
  29. */
  30. //如果叔节点是红色的(父节点有判断是红色). 即是双红色,比较好办,通过改变颜色就行. 把P和U都设置成黑色然后,X加到P节点。 G节点当作新加入节点继续迭代
  31. setColor(parentOf(x), BLACK);
  32. setColor(y, BLACK);
  33. setColor(parentOf(parentOf(x)), RED);
  34. x = parentOf(parentOf(x));
  35. } else {
  36. //处理红父,黑叔的情况
  37. if (x == rightOf(parentOf(x))) {
  38. // 这种情况
  39. /**
  40. * G
  41. * P(RED) U(BLACK)
  42. * X
  43. */
  44. //如果X是右边节点
  45. x = parentOf(x);
  46. // 进行左旋
  47. rotateLeft(x);
  48. }
  49. //左旋后,是这种情况了
  50. /**
  51. * G
  52. * P(RED) U(BLACK)
  53. * X
  54. */
  55.  
  56. // 到这,X只能是左节点了,而且P是红色,U是黑色的情况
  57. //把P和G改成黑色,以G为节点进行右旋
  58. setColor(parentOf(x), BLACK);
  59. setColor(parentOf(parentOf(x)), RED);
  60. rotateRight(parentOf(parentOf(x)));
  61. }
  62. } else {
  63. //父节点在右边的
  64. /**
  65. * G
  66. * U P(RED)
  67. */
  68. //获取U
  69. Entry<K, V> y = leftOf(parentOf(parentOf(x)));
  70.  
  71. if (colorOf(y) == RED) {
  72. //红父红叔的情况
  73. /**
  74. * G
  75. * U(RED) P(RED)
  76. */
  77. setColor(parentOf(x), BLACK);
  78. setColor(y, BLACK);
  79. setColor(parentOf(parentOf(x)), RED);
  80. //把G当作新插入的节点继续进行迭代
  81. x = parentOf(parentOf(x));
  82. } else {
  83. //红父黑叔,并且是右父的情况
  84. /**
  85. * G
  86. * U(RED) P(RED)
  87. */
  88. if (x == leftOf(parentOf(x))) {
  89. x = parentOf(x);
  90. //以P为节点进行右旋
  91. rotateRight(x);
  92. }
  93. //右旋后
  94. /**
  95. * G
  96. * U(BLACK) P(RED)
  97. * X
  98. */
  99. setColor(parentOf(x), BLACK);
  100. setColor(parentOf(parentOf(x)), RED);
  101. //以G为节点进行左旋
  102. rotateLeft(parentOf(parentOf(x)));
  103. }
  104. }
  105. }
  106. //红黑树的根节点始终是黑色
  107. root.color = BLACK;
  108. }

2, HASHMAP的死链问题

  

  1. //对HashMap死链理解的注解 . 2017.02.17 by 何锦彬 JDK,1.7.51
  1. void transfer(Entry[] newTable, boolean rehash) {
  2. //获取新table的容量
  3. int newCapacity = newTable.length;
  4. //迭代以前的数组
  5. for (Entry<K,V> e : table) {
  6. //如果数组上有元素
  7. while(null != e) {
  8. // 赋值next
  9. Entry<K,V> next = e.next;
  10. //获取e在新的table里的位置
  11. if (rehash) {
  12. e.hash = null == e.key ? 0 : hash(e.key);
  13. }
  14. int i = indexFor(e.hash, newCapacity);
  15. //把e指向当前的新数组里的第一个元素,这里会并发了,如果在这断点等待下个线程过来,就会死循环,尝试下
  16. e.next = newTable[i];
  17. //替代新数组的位置
  18. newTable[i] = e;
  19. e = next;
  20. }
  21. }
  22. }

  

扩容前

[ 1 ] [ 2 ] [ 3 ] [ 空]
  5     10

第一个线程扩容后,数组链表如下

[ 1 ] [ 10 ] [3] [] [] [] []
          2

第二个线程又把从头把2指向10,然后2和10形成了个死循环

HashMap在 JDK8后 把数组链表变成了数组+链表+红黑树. 链表为O(n),而红黑树为O(logN)

  1. for (int binCount = 0; ; ++binCount) {
  2. if ((e = p.next) == null) {
  3. p.next = newNode(hash, key, value, null);
  4. //JDK8 的hashmap,链表到了8就需要变成颗红黑树了
  5. if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
  6. treeifyBin(tab, hash);
  7. break;
  8. }

调整红黑树的方法其实和treeMap的一样了

如下:

  1. //hashmap的红黑树平衡
  2. static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
  3. TreeNode<K,V> x) {
  4. x.red = true;
  5. //死循环加变量定义,总感觉JAVA很少这样写代码 哈
  6. for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
  7. //xp X父节点, XPP X的祖父节点, XPPL 祖父左节点 XXPR 祖父右节点
  8. if ((xp = x.parent) == null) {
  9. x.red = false;
  10. return x;
  11. }
  12. // 如果父节点是黑色, 或者XP父节点是空,直接返回
  13. else if (!xp.red || (xpp = xp.parent) == null)
  14. return root;
  15.  
  16. // 下面的代码就和上面的很treeMap像了,
  17.  
  18. if (xp == (xppl = xpp.left)) {
  19. // 第一种情况, 赋值xppl
  20. //父节点是左节点的情况,下面这种
  21. /**
  22. * G
  23. * P(RED) U
  24. */
  25. if ((xppr = xpp.right) != null && xppr.red) {
  26. //如果红叔的情况
  27. // 这种情况
  28. /**
  29. * G
  30. * P(RED) U(RED)
  31. * X
  32. */
  33. //改变其颜色,
  34. xppr.red = false;
  35. xp.red = false;
  36. xpp.red = true;
  37. x = xpp;
  38. }
  39. else {
  40. // 黑叔的情况
  41. // 这种情况
  42. /**
  43. * G
  44. * P(RED) U(BLACK)
  45. */
  46. if (x == xp.right) {
  47. //如果插入节点在右边 这种
  48. // 这种情况
  49. /**
  50. * G
  51. * P(RED) U(BLACK)
  52. * X
  53. */
  54. //需要进行左旋
  55. root = rotateLeft(root, x = xp);
  56. xpp = (xp = x.parent) == null ? null : xp.parent;
  57. }
  58. //左旋后情况都是这种了
  59. /**
  60. * G
  61. * P(RED) U(BLACK)
  62. * X
  63. */
  64. // 到这,X只能是左节点了,而且P是红色,U是黑色的情况
  65. if (xp != null) {
  66. //把P和G改成黑色,以G为节点进行右旋
  67. xp.red = false;
  68. if (xpp != null) {
  69. xpp.red = true;
  70. root = rotateRight(root, xpp);
  71. }
  72. }
  73. }
  74. }
  75. else {
  76. //父节点在右边的
  77. /**
  78. * G
  79. * U P(RED)
  80. */
  81. //获取U
  82. if (xppl != null && xppl.red) {
  83. //红父红叔的情况
  84. /**
  85. * G
  86. * U(RED) P(RED)
  87. */
  88. xppl.red = false;
  89. xp.red = false;
  90. xpp.red = true;
  91. x = xpp;
  92. }
  93. else {
  94.  
  95. if (x == xp.left) {
  96. //如果插入的X是右节点
  97. /**
  98. * G
  99. * U(BLACK) P(RED)
  100. * X
  101. */
  102. root = rotateRight(root, x = xp);
  103. xpp = (xp = x.parent) == null ? null : xp.parent;
  104. }
  105. //右旋后
  106. /**
  107. * G
  108. * U(BLACK) P(RED)
  109. * X
  110. */
  111. if (xp != null) {
  112. xp.red = false;
  113. if (xpp != null) {
  114. xpp.red = true;
  115. root = rotateLeft(root, xpp);
  116. }
  117. }
  118. }
  119. }
  120. }

对把JDK源码的一些注解,笔记的更多相关文章

  1. Integer.parseInt不同jdk源码解析

    执行以下代码: System.out.println(Integer.parseInt("-123")); System.out.println(Integer.parseInt( ...

  2. 一点一点看JDK源码(一)Collection体系概览

    一点一点看JDK源码(一)Collection体系概览 liuyuhang原创,未经允许进制转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 Collection为集 ...

  3. 一点一点看JDK源码(三)java.util.ArrayList 前偏

    一点一点看JDK源码(三)java.util.ArrayList liuyuhang原创,未经允许禁止转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 ArrayLi ...

  4. 如何阅读JDK源码

    JDK源码阅读笔记: https://github.com/kangjianwei/LearningJDK 如何阅读源码,是每个程序员需要面临的一项挑战. 为什么需要阅读源码?从实用性的角度来看,主要 ...

  5. 如何有效的阅读JDK源码

    阅读Java源码的前提条件: 1.技术基础 在阅读源码之前,我们要有一定程度的技术基础的支持. 假如你从来都没有学过Java,也没有其它编程语言的基础,上来就啃<Core Java>,那样 ...

  6. 利用IDEA搭建JDK源码阅读环境

    利用IDEA搭建JDK源码阅读环境 首先新建一个java基础项目 基础目录 source 源码 test 测试源码和入口 准备JDK源码 下图框起来的路径就是jdk的储存位置 打开jdk目录,找到sr ...

  7. 重新编译jdk源码,启用debug信息

    我有一个不知道是好还是不好的习惯,搞不懂的一些玩意儿,喜欢调试然后单步执行看这玩意儿到底是怎么运行的. 今天看到正则表达式的时候,appendReplacement()这个方法怎么也看不明白它是怎么工 ...

  8. 使用NetBeans、Eclipse阅读JDK源码

    下面说明在Netbeans.Eclipse环境下怎么查看JDK源码: Netbeans: 在"工具->java平台->源"里添加下路径,如果你安装jdk的时候选择安装了 ...

  9. eclipse下导入jdk源码

    一直想好好看看jdk的源码,虽然可以直接解压jdk下的src看,但是终究不方便!后来发现可以导入到eclipse中,就在网上找了一些方法,下面就和大家分共享: step1:打开eclipse选择Win ...

随机推荐

  1. UVA - 12050-Palindrome Numbers

    12050 - Palindrome Numbers Time limit: 3.000 seconds A palindrome is a word, number, or phrase that ...

  2. android小说阅读源码、bilibili源码、MVP新闻源码等

    Android精选源码 一款基于 MVP+RxJava2+Retrofit2 的应用--熊猫眼 android 五子棋源码分享 android实现全国地图点击效果 android实现立体图案绘制的代码 ...

  3. webpack + babel

    webpack设计思想:不区分.png .css .js 等文件,都视为一个模块.通过require导入,loader加载器编译之后打包在一个主js文件里. 优势:减少http请求. 1. webpa ...

  4. HDU 1242 Rescue(优先队列)

    题目来源: http://acm.hdu.edu.cn/showproblem.php?pid=1242 题目描述: Problem Description   Angel was caught by ...

  5. DFS算法(——模板习题与总结)

    首先,需要说明的是搜索算法本质上也是枚举的一种,时间复杂度还是很高的,遇到问题(特别是有水平的比赛上),不要优先使用搜索算法. 这里总结一下DFS算法: 1.从图中某个顶点出发,访问v. 2.找出刚访 ...

  6. 基于 fireasy 构建的 asp.net core 示例

    最近花时间弄了一个关于fireasy使用的demo,已放到 github 上供大家研究,https://github.com/faib920/zero 该 demo 演示了如何使用 fireasy 创 ...

  7. Oracle_索引

    Oracle_索引 索引类似字典的和课本目录,是为了加快对数据的搜索速度而设立的.索引有自己专门的存储空间,与表独立存放. 索引的作用:在数据库中用来加速对表的查询,通过使用快速路径访问方法快速定位数 ...

  8. 织梦CMS提示DedeTag Engine Create File False错误的解决办法总结

    今天帮客户升级站点,遇到了一个老问题,生成栏目的时候提示"DedeTag Engine Create File False",突然发觉这个问题竟然在以前做站的时候困扰过我多次,于是 ...

  9. windows下如何创建没有名字的.htaccess文件

    http://www.mdaima.com/jingyan/35.html WINDOWS下建立空名的.htaccess文件 ? 大家都知道,在windows环境下是不能直接建立没有名字的文件的,那我 ...

  10. action之间传参为中文;type='redirect'和 type='redirectAction'主要区别

    摘录自:http://blog.csdn.net/lhi705/article/details/7446156 Struts2中action之间传参中文乱码的问题 解决方法一(已经验证,可以): 两个 ...