﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-CarpenterLee</title><link>http://www.blogjava.net/CarpenterLee/</link><description>技术只是工具，重要的是人才！</description><language>zh-cn</language><lastBuildDate>Sun, 03 May 2026 11:42:05 GMT</lastBuildDate><pubDate>Sun, 03 May 2026 11:42:05 GMT</pubDate><ttl>60</ttl><item><title>Java Stream API入门篇</title><link>http://www.blogjava.net/CarpenterLee/archive/2017/03/29/432420.html</link><dc:creator>CarpenterLee</dc:creator><author>CarpenterLee</author><pubDate>Wed, 29 Mar 2017 13:38:00 GMT</pubDate><guid>http://www.blogjava.net/CarpenterLee/archive/2017/03/29/432420.html</guid><wfw:comment>http://www.blogjava.net/CarpenterLee/comments/432420.html</wfw:comment><comments>http://www.blogjava.net/CarpenterLee/archive/2017/03/29/432420.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/CarpenterLee/comments/commentRss/432420.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/CarpenterLee/services/trackbacks/432420.html</trackback:ping><description><![CDATA[<div id="cnblogs_post_body" class="cnblogs-markdown">
<p><a href="https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/4-Streams%20API(I).md">本文github地址</a><br />
你可能没意识到Java对函数式编程的重视程度，看看Java 8加入函数式编程扩充多少功能就清楚了。Java 8之所以费这么大功夫引入函数式编程，原因有二：</p>
<ol>
     <li><strong>代码简洁</strong>，函数式编程写出的代码简洁且意图明确，使用<em>stream</em>接口让你从此告别<em>for</em>循环。</li>
     <li><strong>多核友好</strong>，Java函数式编程使得编写并行程序从未如此简单，你需要的全部就是调用一下<code>parallel()</code>方法。</li>
</ol>
<p>这一节我们学习<em>stream</em>，也就是Java函数式编程的主角。对于Java 7来说<em>stream</em>完全是个陌生东西，<em>stream</em>并不是某种数据结构，它只是数据源的一种视图。这里的数据源可以是一个数组，Java容器或I/O channel等。正因如此要得到一个<em>stream</em>通常不会手动创建，而是调用对应的工具方法，比如：</p>
<ul>
     <li>调用<code>Collection.stream()</code>或者<code>Collection.parallelStream()</code>方法</li>
     <li>调用<code>Arrays.stream(T[] array)</code>方法</li>
</ul>
<p>常见的<em>stream</em>接口继承关系如图：</p>
<p><img src="http://images2015.cnblogs.com/blog/939998/201703/939998-20170313215540823-221594903.png" width="500px" align="left" alt="Java_stream_Interfaces" /></p>
<p>图中4种<em>stream</em>接口继承自<code>BaseStream</code>，其中<code>IntStream, LongStream, DoubleStream</code>对应三种基本类型（<code>int, long, double</code>，注意不是包装类型），<code>Stream</code>对应所有剩余类型的<em>stream</em>视图。为不同数据类型设置不同<em>stream</em>接口，可以1.提高性能，2.增加特定接口函数。</p>
<p><br />
</p>
<p><img src="http://images2015.cnblogs.com/blog/939998/201703/939998-20170313215634385-204854577.png" width="400px" align="right" alt="WRONG_Java_stream_Interfaces" /></p>
<p>你可能会奇怪为什么不把<code>IntStream</code>等设计成<code>Stream</code>的子接口？毕竟这接口中的方法名大部分是一样的。答案是这些方法的名字虽然相同，但是返回类型不同，如果设计成父子接口关系，这些方法将不能共存，因为Java不允许只有返回类型不同的方法重载。</p>
<p>虽然大部分情况下<em>stream</em>是容器调用<code>Collection.stream()</code>方法得到的，但<em>stream</em>和<em>collections</em>有以下不同：</p>
<ul>
     <li><strong>无存储</strong>。<em>stream</em>不是一种数据结构，它只是某种数据源的一个视图，数据源可以是一个数组，Java容器或I/O channel等。</li>
     <li><strong>为函数式编程而生</strong>。对<em>stream</em>的任何修改都不会修改背后的数据源，比如对<em>stream</em>执行过滤操作并不会删除被过滤的元素，而是会产生一个不包含被过滤元素的新<em>stream</em>。</li>
     <li><strong>惰式执行</strong>。<em>stream</em>上的操作并不会立即执行，只有等到用户真正需要结果的时候才会执行。</li>
     <li><strong>可消费性</strong>。<em>stream</em>只能被&#8220;消费&#8221;一次，一旦遍历过就会失效，就像容器的迭代器那样，想要再次遍历必须重新生成。</li>
</ul>
<p>对<em>stream</em>的操作分为为两类，<strong>中间操作(<em>intermediate operations</em>)和结束操作(<em>terminal operations</em>)</strong>，二者特点是：</p>
<ol>
     <li><strong>中间操作总是会惰式执行</strong>，调用中间操作只会生成一个标记了该操作的新<em>stream</em>，仅此而已。</li>
     <li><strong>结束操作会触发实际计算</strong>，计算发生时会把所有中间操作积攒的操作以<em>pipeline</em>的方式执行，这样可以减少迭代次数。计算完成之后<em>stream</em>就会失效。</li>
</ol>
<p>如果你熟悉Apache Spark RDD，对<em>stream</em>的这个特点应该不陌生。</p>
<p>下表汇总了<code>Stream</code>接口的部分常见方法：</p>
<table>
     <thead>
         <tr class="header">
             <th>操作类型</th><th>接口方法</th>
         </tr>
     </thead>
     <tbody>
         <tr class="odd">
             <td>中间操作</td>
             <td>concat() distinct() filter() flatMap() limit() map() peek() <br />
             skip() sorted() parallel() sequential() unordered()</td>
         </tr>
         <tr class="even">
             <td>结束操作</td>
             <td>allMatch() anyMatch() collect() count() findAny() findFirst() <br />
             forEach() forEachOrdered() max() min() noneMatch() reduce() toArray()</td>
         </tr>
     </tbody>
</table>
<p>区分中间操作和结束操作最简单的方法，就是看方法的返回值，返回值为<em>stream</em>的大都是中间操作，否则是结束操作。</p>
<h2 id="stream方法使用">stream方法使用</h2>
<p><em>stream</em>跟函数接口关系非常紧密，没有函数接口<em>stream</em>就无法工作。回顾一下：<strong>函数接口是指内部只有一个抽象方法的接口</strong>。通常函数接口出现的地方都可以使用Lambda表达式，所以不必记忆函数接口的名字。</p>
<h3 id="foreach">forEach()</h3>
<p>我们对<code>forEach()</code>方法并不陌生，在<code>Collection</code>中我们已经见过。方法签名为<code>void forEach(Consumer&lt;? super E&gt; action)</code>，作用是对容器中的每个元素执行<code>action</code>指定的动作，也就是对元素进行遍历。</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;使用Stream.forEach()迭代</span><span style="color: #008000; "><br />
</span>Stream&lt;String&gt;&nbsp;stream&nbsp;=&nbsp;Stream.of("I",&nbsp;"love",&nbsp;"you",&nbsp;"too");<br />
stream.forEach(str&nbsp;-&gt;&nbsp;System.out.println(str));</div>
<p><br />
由于<code>forEach()</code>是结束方法，上述代码会立即执行，输出所有字符串。</p>
<h3 id="filter">filter()</h3>
<p><img src="http://images2015.cnblogs.com/blog/939998/201703/939998-20170313215744635-60161700.png" width="250px" align="right" hspace="10px" alt="Stream filter" /></p>
<p>函数原型为<code>Stream&lt;T&gt; filter(Predicate&lt;? super T&gt; predicate)</code>，作用是返回一个只包含满足<code>predicate</code>条件元素的<code>Stream</code>。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;保留长度等于3的字符串</span><span style="color: #008000; "><br />
</span>Stream&lt;String&gt;&nbsp;stream=&nbsp;Stream.of("I",&nbsp;"love",&nbsp;"you",&nbsp;"too");<br />
stream.filter(str&nbsp;-&gt;&nbsp;str.length()==3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;.forEach(str&nbsp;-&gt;&nbsp;System.out.println(str));</div>
<div class="sourceCode">
<pre class="sourceCode java"><span style="font-family: verdana, 'courier new';">上述代码将输出为长度等于3的字符串</span><code>you</code><span style="font-family: verdana, 'courier new';">和</span><code>too</code><span style="font-family: verdana, 'courier new';">。注意，由于</span><code>filter()</code><span style="font-family: verdana, 'courier new';">是个中间操作，如果只调用</span><code>filter()</code><span style="font-family: verdana, 'courier new';">不会有实际计算，因此也不会输出任何信息。</span></pre>
</div>
<h3 id="distinct">distinct()</h3>
<p><img src="http://images2015.cnblogs.com/blog/939998/201703/939998-20170313215820213-2027403065.png" width="200px" align="left" hspace="10px" alt="Stream distinct" /></p>
<p>函数原型为<code>Stream&lt;T&gt; distinct()</code>，作用是返回一个去除重复元素之后的<code>Stream</code>。</p>
<div class="sourceCode">
<pre class="sourceCode java"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->Stream&lt;String&gt;&nbsp;stream=&nbsp;Stream.of("I",&nbsp;"love",&nbsp;"you",&nbsp;"too",&nbsp;"too");
stream.distinct()
&nbsp;&nbsp;&nbsp;&nbsp;.forEach(str&nbsp;-&gt;&nbsp;System.out.println(str));</div>
</pre>
</div>
<p>上述代码会输出去掉一个<code>too</code>之后的其余字符串。</p>
<p><br /></p><h3 id="sorted">
sorted()</h3>
<p>排序函数有两个，一个是用自然顺序排序，一个是使用自定义比较器排序，函数原型分别为<code>Stream&lt;T&gt;　sorted()</code>和<code>Stream&lt;T&gt;　sorted(Comparator&lt;? super T&gt; comparator)</code>。</p>
<div class="sourceCode">
<pre class="sourceCode java"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->Stream&lt;String&gt;&nbsp;stream=&nbsp;Stream.of("I",&nbsp;"love",&nbsp;"you",&nbsp;"too");
stream.sorted((str1,&nbsp;str2)&nbsp;-&gt;&nbsp;str1.length()-str2.length())
&nbsp;&nbsp;&nbsp;&nbsp;.forEach(str&nbsp;-&gt;&nbsp;System.out.println(str));</div>
</pre>
</div>
<p>上述代码将输出按照长度升序排序后的字符串，结果完全在预料之中。</p>
<h3 id="map">map()</h3>
<p><img src="http://images2015.cnblogs.com/blog/939998/201703/939998-20170313215854807-2125107413.png" width="250px" align="right" hspace="10px" alt="Stream map" /></p>
<p>函数原型为<code>&lt;R&gt; Stream&lt;R&gt; map(Function&lt;? super T,? extends R&gt; mapper)</code>，作用是返回一个对当前所有元素执行执行<code>mapper</code>之后的结果组成的<code>Stream</code>。直观的说，就是对每个元素按照某种操作进行转换，转换前后<code>Stream</code>中元素的个数不会改变，但元素的类型取决于转换之后的类型。</p>
<div class="sourceCode">
<pre class="sourceCode java"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->Stream&lt;String&gt;&nbsp;stream　=&nbsp;Stream.of("I",&nbsp;"love",&nbsp;"you",&nbsp;"too");
stream.map(str&nbsp;-&gt;&nbsp;str.toUpperCase())
&nbsp;&nbsp;&nbsp;&nbsp;.forEach(str&nbsp;-&gt;&nbsp;System.out.println(str));</div>
</pre>
</div>
<p>上述代码将输出原字符串的大写形式。</p>
<h3 id="flatmap">flatMap()</h3>
<p><img src="http://images2015.cnblogs.com/blog/939998/201703/939998-20170313215941870-1457129851.png" width="300px" align="left" hspace="10px" alt="Stream flatMap" /></p>
<p>函数原型为<code>&lt;R&gt; Stream&lt;R&gt; flatMap(Function&lt;? super T,? extends Stream&lt;? extends R&gt;&gt; mapper)</code>，作用是对每个元素执行<code>mapper</code>指定的操作，并用所有<code>mapper</code>返回的<code>Stream</code>中的元素组成一个新的<code>Stream</code>作为最终返回结果。说起来太拗口，通俗的讲<code>flatMap()</code>的作用就相当于把原<em>stream</em>中的所有元素都"摊平"之后组成的<code>Stream</code>，转换前后元素的个数和类型都可能会改变。</p>
<div class="sourceCode">
<pre class="sourceCode java"><div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->Stream&lt;List&lt;Integer&gt;&gt;&nbsp;stream&nbsp;=&nbsp;Stream.of(Arrays.asList(1,2),&nbsp;Arrays.asList(3,&nbsp;4,&nbsp;5));<br />stream.flatMap(list&nbsp;-&gt;&nbsp;list.stream())<br />&nbsp;&nbsp;&nbsp;&nbsp;.forEach(i&nbsp;-&gt;&nbsp;System.out.println(i));</div>
</pre>
</div>
<p>上述代码中，原来的<code>stream</code>中有两个元素，分别是两个<code>List&lt;Integer&gt;</code>，执行<code>flatMap()</code>之后，将每个<code>List</code>都&#8220;摊平&#8221;成了一个个的数字，所以会新产生一个由5个数字组成的<code>Stream</code>。所以最终将输出1~5这5个数字。</p>
<h2 id="结语">结语</h2>
<p>截止到目前我们感觉良好，已介绍<code>Stream</code>API理解起来并不费劲儿。如果你就此以为函数式编程不过如此，恐怕是高兴地太早了。下一节对<a href="http://www.cnblogs.com/CarpenterLee/p/6550212.html"><code>Stream</code>规约操作</a>的介绍将刷新你现在的认识。</p>
<p><a href="https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/4-Streams%20API(I).md">本文github地址</a>，欢迎关注。</p>
</div><img src ="http://www.blogjava.net/CarpenterLee/aggbug/432420.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/CarpenterLee/" target="_blank">CarpenterLee</a> 2017-03-29 21:38 <a href="http://www.blogjava.net/CarpenterLee/archive/2017/03/29/432420.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《深入理解Java集合框架》系列文章</title><link>http://www.blogjava.net/CarpenterLee/archive/2016/05/31/430716.html</link><dc:creator>CarpenterLee</dc:creator><author>CarpenterLee</author><pubDate>Tue, 31 May 2016 07:28:00 GMT</pubDate><guid>http://www.blogjava.net/CarpenterLee/archive/2016/05/31/430716.html</guid><wfw:comment>http://www.blogjava.net/CarpenterLee/comments/430716.html</wfw:comment><comments>http://www.blogjava.net/CarpenterLee/archive/2016/05/31/430716.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/CarpenterLee/comments/commentRss/430716.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/CarpenterLee/services/trackbacks/430716.html</trackback:ping><description><![CDATA[<div id="cnblogs_post_body" class="cnblogs-markdown"><h1 id="introduction">Introduction</h1><p>关于<em>C++标准模板库(Standard Template Library, STL)</em>的书籍和资料有很多，关于<em>Java集合框架(Java Collections Framework, JCF)</em>的资料却很少，甚至很难找到一本专门介绍它的书籍，这给Java学习者们带来不小的麻烦。我深深的不解其中的原因。<strong>虽然JCF设计参考了STL，但其定位不是Java版的STL，而是要实现一个精简紧凑的容器框架</strong>，对STL的介绍自然不能替代对JCF的介绍。</p><p>本系列文章主要从<strong>数据结构和算法</strong>层面分析JCF中List, Set, Map, Stack, Queue等典型容器，<strong>结合生动图解和源代码，帮助读者对Java集合框架建立清晰而深入的理解</strong>。本文并不特意介绍Java的语言特性，但会在需要的时候做出简洁的解释。</p><h1 id="contents">Contents</h1><p>具体内容安排如下：</p><ol><li><a href="http://www.cnblogs.com/CarpenterLee/p/5414253.html">Java Collections Framework概览</a> 对Java Collections Framework，以及Java语言特性做出基本介绍。</li><li><a href="http://www.cnblogs.com/CarpenterLee/p/5419880.html">Java ArrayList源码剖析</a> 结合源码对<em>ArrayList</em>进行讲解。</li><li><a href="http://www.cnblogs.com/CarpenterLee/p/5457150.html">Java LinkedList源码剖析</a> 结合源码对<em>LinkedList</em>进行讲解。</li><li><a href="http://www.cnblogs.com/CarpenterLee/p/5468803.html">Java ArrayDeque源码剖析</a> 以<em>AarryDeque</em>为例讲解<em>Stack</em>和<em>Queue</em>。</li><li><a href="http://www.cnblogs.com/CarpenterLee/p/5503882.html">史上最清晰的红黑树讲解（上）</a>和<a href="http://www.cnblogs.com/CarpenterLee/p/5525688.html">史上最清晰的红黑树讲解（下）</a> 结合源码对<em>TreeSet</em>和<em>TreeMap</em>进行讲解。</li><li><a href="http://www.cnblogs.com/CarpenterLee/p/5440428.html">Java HashSet和HashMap源码剖析</a> 结合源码对<em>HashSet</em>和<em>HashMap</em>进行讲解。</li><li><a href="http://www.cnblogs.com/CarpenterLee/p/5541111.html">Java集合框架源码剖析：LinkedHashSet 和 LinkedHashMap</a> 结合源码对<em>LinkedHashSet</em>和<em>LinkedHashMap</em>进行讲解。</li><li><a href="http://www.cnblogs.com/CarpenterLee/p/5488070.html">深入理解Java PriorityQueue</a> 结合源码对<em>PriorityQueue</em>进行讲解。</li><li><a href="https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/9-WeakHashMap.md">浅谈WeakHashMap</a> 对<em>WeakHashMap</em>做出基本介绍。</li></ol><h1 id="authors">Authors</h1><table><thead><tr class="header"><th align="left">Name</th><th align="left">Weibo Id</th><th align="left">GitHub</th><th align="left">Mail</th></tr></thead><tbody><tr class="odd"><td align="left">李豪</td><td align="left"><a href="http://weibo.com/icttinymouse">@计算所的小鼠标</a></td><td align="left"><a href="https://github.com/CarpenterLee/JCFInternals">CarpenterLee</a></td><td align="left"><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#104;&#111;&#111;&#108;&#101;&#101;&#117;&#99;&#97;&#115;&#64;&#49;&#54;&#51;&#46;&#99;&#111;&#109;">hooleeucas@163.com</a></td></tr></tbody></table><p><strong><br />以上所有博文均在<a href="https://github.com/CarpenterLee/JCFInternals">博主GitHub</a>上有副本，并且能保证最新版本。欢迎各位博友关注</strong>。<br /><br /></p></div><img src ="http://www.blogjava.net/CarpenterLee/aggbug/430716.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/CarpenterLee/" target="_blank">CarpenterLee</a> 2016-05-31 15:28 <a href="http://www.blogjava.net/CarpenterLee/archive/2016/05/31/430716.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅谈WeakHashMap</title><link>http://www.blogjava.net/CarpenterLee/archive/2016/05/31/430712.html</link><dc:creator>CarpenterLee</dc:creator><author>CarpenterLee</author><pubDate>Mon, 30 May 2016 23:27:00 GMT</pubDate><guid>http://www.blogjava.net/CarpenterLee/archive/2016/05/31/430712.html</guid><wfw:comment>http://www.blogjava.net/CarpenterLee/comments/430712.html</wfw:comment><comments>http://www.blogjava.net/CarpenterLee/archive/2016/05/31/430712.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/CarpenterLee/comments/commentRss/430712.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/CarpenterLee/services/trackbacks/430712.html</trackback:ping><description><![CDATA[<div id="cnblogs_post_body" class="cnblogs-markdown"><p>Java <em>WeakHashMap</em> 到底Weak在哪里，它真的很弱吗？<em>WeakHashMap</em> 的适用场景是什么，使用时需要注意些什么？弱引用和强引用对Java GC有什么不同影响？本文将给出清晰而简洁的介绍。</p><h1 id="总体介绍">总体介绍</h1><p>在Java集合框架系列文章的最后，笔者打算介绍一个特殊的成员：<em>WeakHashMap</em>，从名字可以看出它是某种 <em>Map</em>。它的特殊之处在于 <em>WeakHashMap</em> 里的<code>entry</code>可能会被GC自动删除，即使程序员没有调用<code>remove()</code>或者<code>clear()</code>方法。</p><p>更直观的说，当使用 <em>WeakHashMap</em> 时，即使没有显示的添加或删除任何元素，也可能发生如下情况：</p><blockquote><ul><li>调用两次<code>size()</code>方法返回不同的值；</li><li>两次调用<code>isEmpty()</code>方法，第一次返回<code>false</code>，第二次返回<code>true</code>；</li><li>两次调用<code>containsKey()</code>方法，第一次返回<code>true</code>，第二次返回<code>false</code>，尽管两次使用的是同一个<code>key</code>；</li><li>两次调用<code>get()</code>方法，第一次返回一个<code>value</code>，第二次返回<code>null</code>，尽管两次使用的是同一个对象。</li></ul></blockquote><p>遇到这么奇葩的现象，你是不是觉得使用者一定会疯掉？其实不然，<strong><em>WeekHashMap</em> 的这个特点特别适用于需要缓存的场景</strong>。在缓存场景下，由于内存是有限的，不能缓存所有对象；对象缓存命中可以提高系统效率，但缓存MISS也不会造成错误，因为可以通过计算重新得到。</p><p>要明白 <em>WeekHashMap</em> 的工作原理，还需要引入一个概念：<strong>弱引用（WeakReference）</strong>。我们都知道Java中内存是通过GC自动管理的，GC会在程序运行过程中自动判断哪些对象是可以被回收的，并在合适的时机进行内存释放。GC判断某个对象是否可被回收的依据是，<strong>是否有有效的引用指向该对象</strong>。如果没有有效引用指向该对象（基本意味着不存在访问该对象的方式），那么该对象就是可回收的。这里的<strong>&#8220;有效引用&#8221;</strong>并不包括<strong>弱引用</strong>。也就是说，<strong>虽然弱引用可以用来访问对象，但进行垃圾回收时弱引用并不会被考虑在内，仅有弱引用指向的对象仍然会被GC回收</strong>。</p><p><em>WeakHashMap</em> 内部是通过弱引用来管理<code>entry</code>的，弱引用的特性对应到 <em>WeakHashMap</em> 上意味着什么呢？<strong>将一对<code>key, value</code>放入到 <em>WeakHashMap</em> 里并不能避免该<code>key</code>值被GC回收，除非在 <em>WeakHashMap</em> 之外还有对该<code>key</code>的强引用</strong>。</p><p>关于强引用，弱引用等概念以后再具体讲解，这里只需要知道Java中引用也是分种类的，并且不同种类的引用对GC的影响不同就够了。</p><h1 id="具体实现">具体实现</h1><p>WeakHashMap的存储结构类似于HashMap，读者可自行<a href="https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/6-HashSet%20and%20HashMap.md">参考前文</a>，这里不再赘述。</p><p>关于强弱引用的管理方式，博主将会另开专题单独讲解。</p><h1 id="weak-hashset">Weak HashSet?</h1><p>如果你看过前几篇关于 <em>Map</em> 和 <em>Set</em> 的讲解，一定会问：既然有 <em>WeekHashMap</em>，是否有 <em>WeekHashSet</em> 呢？答案是没有:( 。不过Java <em>Collections</em>工具类给出了解决方案，<code>Collections.newSetFromMap(Map&lt;E,Boolean&gt; map)</code>方法可以将任何 <em>Map</em>包装成一个<em>Set</em>。通过如下方式可以快速得到一个 <em>Weak HashSet</em>：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;将WeakHashMap包装成一个Set</span><span style="color: #008000; "><br /></span>Set&lt;Object&gt;&nbsp;weakHashSet&nbsp;=&nbsp;Collections.newSetFromMap(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;WeakHashMap&lt;Object,&nbsp;Boolean&gt;());</div><p>不出你所料，<code>newSetFromMap()</code>方法只是对传入的 <em>Map</em>做了简单包装：<br /></p><div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Collections.newSetFromMap()用于将任何Map包装成一个Set</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;&lt;E&gt;&nbsp;Set&lt;E&gt;&nbsp;newSetFromMap(Map&lt;E,&nbsp;Boolean&gt;&nbsp;map)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;SetFromMap&lt;&gt;(map);<br />}<br /><br /><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;SetFromMap&lt;E&gt;&nbsp;<span style="color: #0000FF; ">extends</span>&nbsp;AbstractSet&lt;E&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">implements</span>&nbsp;Set&lt;E&gt;,&nbsp;Serializable<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Map&lt;E,&nbsp;Boolean&gt;&nbsp;m;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;The&nbsp;backing&nbsp;map</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">transient</span>&nbsp;Set&lt;E&gt;&nbsp;s;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Its&nbsp;keySet</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;SetFromMap(Map&lt;E,&nbsp;Boolean&gt;&nbsp;map)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(!map.isEmpty())<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">throw</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;IllegalArgumentException("Map&nbsp;is&nbsp;non-empty");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m&nbsp;=&nbsp;map;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;map.keySet();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;clear()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m.clear();&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;size()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;m.size();&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;isEmpty()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;m.isEmpty();&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;contains(Object&nbsp;o)&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;m.containsKey(o);&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;remove(Object&nbsp;o)&nbsp;&nbsp;&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;m.remove(o)&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;add(E&nbsp;e)&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;m.put(e,&nbsp;Boolean.TRUE)&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;Iterator&lt;E&gt;&nbsp;iterator()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;s.iterator();&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;Object[]&nbsp;toArray()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;s.toArray();&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;&lt;T&gt;&nbsp;T[]&nbsp;toArray(T[]&nbsp;a)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;s.toArray(a);&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;toString()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;s.toString();&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;hashCode()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;s.hashCode();&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;equals(Object&nbsp;o)&nbsp;&nbsp;&nbsp;{&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;o&nbsp;==&nbsp;<span style="color: #0000FF; ">this</span>&nbsp;||&nbsp;s.equals(o);&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;containsAll(Collection&lt;?&gt;&nbsp;c)&nbsp;{<span style="color: #0000FF; ">return</span>&nbsp;s.containsAll(c);}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;removeAll(Collection&lt;?&gt;&nbsp;c)&nbsp;&nbsp;&nbsp;{<span style="color: #0000FF; ">return</span>&nbsp;s.removeAll(c);}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;retainAll(Collection&lt;?&gt;&nbsp;c)&nbsp;&nbsp;&nbsp;{<span style="color: #0000FF; ">return</span>&nbsp;s.retainAll(c);}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;addAll&nbsp;is&nbsp;the&nbsp;only&nbsp;inherited&nbsp;implementation</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />}</div><h1 id="结语">结语</h1><p>至此<em><a href="https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/0-Introduction.md">深入Java集合框架(Java Collections Framework Internals)</a></em>系列已经全部讲解完毕，希望这几篇简短的博文能够帮助各位读者对Java容器框架建立基本的理解。通过这里可以返回<a href="https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/0-Introduction.md">本系列文章目录</a>。</p><p>如果对各位有哪怕些微的帮助，博主将感到非常高兴！如果博文中有任何的纰漏和谬误，欢迎各位博友指正。</p><p><a href="https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/9-WeakHashMap.md">本文GitHub地址</a></p></div><img src ="http://www.blogjava.net/CarpenterLee/aggbug/430712.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/CarpenterLee/" target="_blank">CarpenterLee</a> 2016-05-31 07:27 <a href="http://www.blogjava.net/CarpenterLee/archive/2016/05/31/430712.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java集合框架源码剖析：LinkedHashSet 和 LinkedHashMap</title><link>http://www.blogjava.net/CarpenterLee/archive/2016/05/30/430703.html</link><dc:creator>CarpenterLee</dc:creator><author>CarpenterLee</author><pubDate>Mon, 30 May 2016 01:19:00 GMT</pubDate><guid>http://www.blogjava.net/CarpenterLee/archive/2016/05/30/430703.html</guid><wfw:comment>http://www.blogjava.net/CarpenterLee/comments/430703.html</wfw:comment><comments>http://www.blogjava.net/CarpenterLee/archive/2016/05/30/430703.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/CarpenterLee/comments/commentRss/430703.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/CarpenterLee/services/trackbacks/430703.html</trackback:ping><description><![CDATA[<div id="cnblogs_post_body" class="cnblogs-markdown"><p>Java <em>LinkedHashMap</em>和<em>HashMap</em>有什么区别和联系？为什么<em>LinkedHashMap</em>会有着更快的迭代速度？<em>LinkedHashSet</em>跟<em>LinkedHashMap</em>有着怎样的内在联系？本文从数据结构和算法层面，结合生动图解为读者一一解答。</p><p><a href="https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/7-LinkedHashSet%20and%20LinkedHashMap.md">本文github地址</a></p><h1 id="总体介绍">总体介绍</h1><p>如果你已看过前面关于<em>HashSet</em>和<em>HashMap</em>，以及<em>TreeSet</em>和<em>TreeMap</em>的讲解，一定能够想到本文将要讲解的<em>LinkedHashSet</em>和<em>LinkedHashMap</em>其实也是一回事。<em>LinkedHashSet</em>和<em>LinkedHashMap</em>在Java里也有着相同的实现，前者仅仅是对后者做了一层包装，也就是说<strong><em>LinkedHashSet</em>里面有一个<em>LinkedHashMap</em>（适配器模式）</strong>。因此本文将重点分析<em>LinkedHashMap</em>。</p><p><em>LinkedHashMap</em>实现了<em>Map</em>接口，即允许放入<code>key</code>为<code>null</code>的元素，也允许插入<code>value</code>为<code>null</code>的元素。从名字上可以看出该容器是<em>linked list</em>和<em>HashMap</em>的混合体，也就是说它同时满足<em>HashMap</em>和<em>linked list</em>的某些特性。<strong>可将<em>LinkedHashMap</em>看作采用<em>linked list</em>增强的<em>HashMap</em>。</strong></p><p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160528192537725-909052596.png" alt="LinkedHashMap_base.png" width="800" height="700" /></p><p>事实上<em>LinkedHashMap</em>是<em>HashMap</em>的直接子类，<strong>二者唯一的区别是<em>LinkedHashMap</em>在<em>HashMap</em>的基础上，采用双向链表（doubly-linked list）的形式将所有<code>entry</code>连接起来，这样是为保证元素的迭代顺序跟插入顺序相同</strong>。上图给出了<em>LinkedHashMap</em>的结构图，主体部分跟<em>HashMap</em>完全一样，多了<code>header</code>指向双向链表的头部（是一个哑元），<strong>该双向链表的迭代顺序就是<code>entry</code>的插入顺序</strong>。</p><p>除了可以保迭代历顺序，这种结构还有一个好处：<strong>迭代<em>LinkedHashMap</em>时不需要像<em>HashMap</em>那样遍历整个<code>table</code>，而只需要直接遍历<code>header</code>指向的双向链表即可</strong>，也就是说<em>LinkedHashMap</em>的迭代时间就只跟<code>entry</code>的个数相关，而跟<code>table</code>的大小无关。</p><p>有两个参数可以影响<em>LinkedHashMap</em>的性能：初始容量（inital capacity）和负载系数（load factor）。初始容量指定了初始<code>table</code>的大小，负载系数用来指定自动扩容的临界值。当<code>entry</code>的数量超过<code>capacity*load_factor</code>时，容器将自动扩容并重新哈希。对于插入元素较多的场景，将初始容量设大可以减少重新哈希的次数。</p><p>将对象放入到<em>LinkedHashMap</em>或<em>LinkedHashSet</em>中时，有两个方法需要特别关心：<code>hashCode()</code>和<code>equals()</code>。<strong><code>hashCode()</code>方法决定了对象会被放到哪个<code>bucket</code>里，当多个对象的哈希值冲突时，<code>equals()</code>方法决定了这些对象是否是&#8220;同一个对象&#8221;</strong>。所以，如果要将自定义的对象放入到<code>LinkedHashMap</code>或<code>LinkedHashSet</code>中，<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#38656;&#35201;&#42;&#64;&#79;&#118;&#101;&#114;&#114;&#105;&#100;&#101;&#42;">需要*@Override*</a><code>hashCode()</code>和<code>equals()</code>方法。</p><p>通过如下方式可以得到一个跟源<em>Map</em><strong>迭代顺序</strong>一样的<em>LinkedHashMap</em>：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">void</span>&nbsp;foo(Map&nbsp;m)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;Map&nbsp;copy&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;LinkedHashMap(m);<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />}</div><p>出于性能原因，<em>LinkedHashMap</em>是非同步的（not synchronized），如果需要在多线程环境使用，需要程序员手动同步；或者通过如下方式将<em>LinkedHashMap</em>包装成（wrapped）同步的：</p><p><code>Map m = Collections.synchronizedMap(new LinkedHashMap(...));</code></p><h1 id="方法剖析">方法剖析</h1><h2 id="get">get()</h2><p><code>get(Object key)</code>方法根据指定的<code>key</code>值返回对应的<code>value</code>。该方法跟<code>HashMap.get()</code>方法的流程几乎完全一样，读者可自行<a href="http://www.cnblogs.com/CarpenterLee/p/5440428.html">参考前文</a>，这里不再赘述。</p><h2 id="put">put()</h2><p><code>put(K key, V value)</code>方法是将指定的<code>key, value</code>对添加到<code>map</code>里。该方法首先会对<code>map</code>做一次查找，看是否包含该元组，如果已经包含则直接返回，查找过程类似于<code>get()</code>方法；如果没有找到，则会通过<code>addEntry(int hash, K key, V value, int bucketIndex)</code>方法插入新的<code>entry</code>。</p><p>注意，这里的<strong>插入有两重含义</strong>：</p><blockquote><ol><li>从<code>table</code>的角度看，新的<code>entry</code>需要插入到对应的<code>bucket</code>里，当有哈希冲突时，采用头插法将新的<code>entry</code>插入到冲突链表的头部。</li><li>从<code>header</code>的角度看，新的<code>entry</code>需要插入到双向链表的尾部。</li></ol></blockquote><p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160528192545084-2117175891.png" alt="LinkedHashMap_addEntry.png" width="800" height="694" /></p><p><code>addEntry()</code>代码如下：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;LinkedHashMap.addEntry()</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">void</span>&nbsp;addEntry(<span style="color: #0000FF; ">int</span>&nbsp;hash,&nbsp;K&nbsp;key,&nbsp;V&nbsp;value,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;bucketIndex)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;((size&nbsp;&gt;=&nbsp;threshold)&nbsp;&amp;&amp;&nbsp;(<span style="color: #0000FF; ">null</span>&nbsp;!=&nbsp;table[bucketIndex]))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resize(2&nbsp;*&nbsp;table.length);<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;自动扩容，并重新哈希</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hash&nbsp;=&nbsp;(<span style="color: #0000FF; ">null</span>&nbsp;!=&nbsp;key)&nbsp;?&nbsp;hash(key)&nbsp;:&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bucketIndex&nbsp;=&nbsp;hash&nbsp;&amp;&nbsp;(table.length-1);<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;hash%table.length</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;1.在冲突链表头部插入新的entry</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;HashMap.Entry&lt;K,V&gt;&nbsp;old&nbsp;=&nbsp;table[bucketIndex];<br />&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;e&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Entry&lt;&gt;(hash,&nbsp;key,&nbsp;value,&nbsp;old);<br />&nbsp;&nbsp;&nbsp;&nbsp;table[bucketIndex]&nbsp;=&nbsp;e;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;2.在双向链表的尾部插入新的entry</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;e.addBefore(header);<br />&nbsp;&nbsp;&nbsp;&nbsp;size++;<br />}</div><p>上述代码中用到了<code>addBefore()</code>方法将新<code>entry e</code>插入到双向链表头引用<code>header</code>的前面，这样<code>e</code>就成为双向链表中的最后一个元素。<code>addBefore()</code>的代码如下：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;LinkedHashMap.Entry.addBefor()，将this插入到existingEntry的前面</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;addBefore(Entry&lt;K,V&gt;&nbsp;existingEntry)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;after&nbsp;&nbsp;=&nbsp;existingEntry;<br />&nbsp;&nbsp;&nbsp;&nbsp;before&nbsp;=&nbsp;existingEntry.before;<br />&nbsp;&nbsp;&nbsp;&nbsp;before.after&nbsp;=&nbsp;<span style="color: #0000FF; ">this</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;after.before&nbsp;=&nbsp;<span style="color: #0000FF; ">this</span>;<br />}</div><p>上述代码只是简单修改相关<code>entry</code>的引用而已。</p><h2 id="remove">remove()</h2><p><code>remove(Object key)</code>的作用是删除<code>key</code>值对应的<code>entry</code>，该方法的具体逻辑是在<code>removeEntryForKey(Object key)</code>里实现的。<code>removeEntryForKey()</code>方法会首先找到<code>key</code>值对应的<code>entry</code>，然后删除该<code>entry</code>（修改链表的相应引用）。查找过程跟<code>get()</code>方法类似。</p><p>注意，这里的<strong>删除也有两重含义</strong>：</p><blockquote><ol><li>从<code>table</code>的角度看，需要将该<code>entry</code>从对应的<code>bucket</code>里删除，如果对应的冲突链表不空，需要修改冲突链表的相应引用。</li><li>从<code>header</code>的角度来看，需要将该<code>entry</code>从双向链表中删除，同时修改链表中前面以及后面元素的相应引用。</li></ol></blockquote><p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160528192553897-96073839.png" alt="LinkedHashMap_removeEntryForKey.png" width="800" height="643" /></p><p><code>removeEntryForKey()</code>对应的代码如下：<br /></p><div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;LinkedHashMap.removeEntryForKey()，删除key值对应的entry</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">final</span>&nbsp;Entry&lt;K,V&gt;&nbsp;removeEntryForKey(Object&nbsp;key)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;hash&nbsp;=&nbsp;(key&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;?&nbsp;0&nbsp;:&nbsp;hash(key);<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;i&nbsp;=&nbsp;indexFor(hash,&nbsp;table.length);<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;hash&amp;(table.length-1)</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;prev&nbsp;=&nbsp;table[i];<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;得到冲突链表</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;e&nbsp;=&nbsp;prev;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(e&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;遍历冲突链表</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;next&nbsp;=&nbsp;e.next;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;k;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(e.hash&nbsp;==&nbsp;hash&nbsp;&amp;&amp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((k&nbsp;=&nbsp;e.key)&nbsp;==&nbsp;key&nbsp;||&nbsp;(key&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>&nbsp;&amp;&amp;&nbsp;key.equals(k))))&nbsp;{<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;找到要删除的entry</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modCount++;&nbsp;size--;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;1.&nbsp;将e从对应bucket的冲突链表中删除</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(prev&nbsp;==&nbsp;e)&nbsp;table[i]&nbsp;=&nbsp;next;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;prev.next&nbsp;=&nbsp;next;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;2.&nbsp;将e从双向链表中删除</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.before.after&nbsp;=&nbsp;e.after;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.after.before&nbsp;=&nbsp;e.before;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;e;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prev&nbsp;=&nbsp;e;&nbsp;e&nbsp;=&nbsp;next;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;e;<br />}</div><h1 id="linkedhashset">LinkedHashSet</h1><p>前面已经说过<em>LinkedHashSet</em>是对<em>LinkedHashMap</em>的简单包装，对<em>LinkedHashSet</em>的函数调用都会转换成合适的<em>LinkedHashMap</em>方法，因此<em>LinkedHashSet</em>的实现非常简单，这里不再赘述。<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;LinkedHashSet&lt;E&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">extends</span>&nbsp;HashSet&lt;E&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">implements</span>&nbsp;Set&lt;E&gt;,&nbsp;Cloneable,&nbsp;java.io.Serializable&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;LinkedHashSet里面有一个LinkedHashMap</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;LinkedHashSet(<span style="color: #0000FF; ">int</span>&nbsp;initialCapacity,&nbsp;<span style="color: #0000FF; ">float</span>&nbsp;loadFactor)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;LinkedHashMap&lt;&gt;(initialCapacity,&nbsp;loadFactor);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;add(E&nbsp;e)&nbsp;{<span style="color: #008000; ">//</span><span style="color: #008000; ">简单的方法转换</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;map.put(e,&nbsp;PRESENT)==<span style="color: #0000FF; ">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />}</div></div><img src ="http://www.blogjava.net/CarpenterLee/aggbug/430703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/CarpenterLee/" target="_blank">CarpenterLee</a> 2016-05-30 09:19 <a href="http://www.blogjava.net/CarpenterLee/archive/2016/05/30/430703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>史上最清晰的红黑树讲解（下）</title><link>http://www.blogjava.net/CarpenterLee/archive/2016/05/25/430645.html</link><dc:creator>CarpenterLee</dc:creator><author>CarpenterLee</author><pubDate>Wed, 25 May 2016 08:48:00 GMT</pubDate><guid>http://www.blogjava.net/CarpenterLee/archive/2016/05/25/430645.html</guid><wfw:comment>http://www.blogjava.net/CarpenterLee/comments/430645.html</wfw:comment><comments>http://www.blogjava.net/CarpenterLee/archive/2016/05/25/430645.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/CarpenterLee/comments/commentRss/430645.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/CarpenterLee/services/trackbacks/430645.html</trackback:ping><description><![CDATA[<div id="cnblogs_post_body" class="cnblogs-markdown"><p><a href="https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/5-TreeSet%20and%20TreeMap.md">本文github地址</a></p><p>上一篇文章<a href="http://www.cnblogs.com/CarpenterLee/p/5503882.html">史上最清晰的红黑树讲解（上）</a>对Java <em>TreeMap</em>的插入以及插入之后的调整过程给出了详述。<strong>本文接着以Java <em>TreeMap</em>为例，从源码层面讲解红黑树的删除，以及删除之后的调整过程</strong>。如果还没有看过上一篇文章，请在阅读本文之前大致浏览一下前文，以方便理解。</p><h2 id="寻找节点后继">寻找节点后继</h2><p>对于一棵二叉查找树，给定节点t，其后继（树种比大于t的最小的那个元素）可以通过如下方式找到：</p><blockquote><ol><li>t的右子树不空，则t的后继是其右子树中最小的那个元素。</li><li>t的右孩子为空，则t的后继是其第一个向左走的祖先。</li></ol></blockquote><p>后继节点在红黑树的删除操作中将会用到。</p><p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160525090153256-1268136762.png" alt="TreeMap_successor.png" width="800" height="379" /></p><p><em>TreeMap</em>中寻找节点后继的代码如下：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;寻找节点后继函数successor()</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">static</span>&nbsp;&lt;K,V&gt;&nbsp;TreeMap.Entry&lt;K,V&gt;&nbsp;successor(Entry&lt;K,V&gt;&nbsp;t)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(t&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(t.right&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;1.&nbsp;t的右子树不空，则t的后继是其右子树中最小的那个元素</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;p&nbsp;=&nbsp;t.right;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(p.left&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;=&nbsp;p.left;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;p;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;2.&nbsp;t的右孩子为空，则t的后继是其第一个向左走的祖先</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;p&nbsp;=&nbsp;t.parent;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;ch&nbsp;=&nbsp;t;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(p&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>&nbsp;&amp;&amp;&nbsp;ch&nbsp;==&nbsp;p.right)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ch&nbsp;=&nbsp;p;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;=&nbsp;p.parent;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;p;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><div class="sourceCode"><pre class="sourceCode java"><br /></pre></div><h2 id="remove">remove()</h2><p><code>remove(Object key)</code>的作用是删除<code>key</code>值对应的<code>entry</code>，该方法首先通过上文中提到的<code>getEntry(Object key)</code>方法找到<code>key</code>值对应的<code>entry</code>，然后调用<code>deleteEntry(Entry&lt;K,V&gt; entry)</code>删除对应的<code>entry</code>。由于删除操作会改变红黑树的结构，有可能破坏红黑树的约束条件，因此有可能要进行调整。</p><p><code>getEntry()</code>函数前面已经讲解过，这里重点放<code>deleteEntry()</code>上，该函数删除指定的<code>entry</code>并在红黑树的约束被破坏时进行调用<code>fixAfterDeletion(Entry&lt;K,V&gt; x)</code>进行调整。</p><p><strong>由于红黑树是一棵增强版的二叉查找树，红黑树的删除操作跟普通二叉查找树的删除操作也就非常相似，唯一的区别是红黑树在节点删除之后可能需要进行调整</strong>。现在考虑一棵普通二叉查找树的删除过程，可以简单分为两种情况：</p><blockquote><ol><li>删除点p的左右子树都为空，或者只有一棵子树非空。</li><li>删除点p的左右子树都非空。</li></ol></blockquote><p>对于上述情况1，处理起来比较简单，直接将p删除（左右子树都为空时），或者用非空子树替代p（只有一棵子树非空时）；对于情况2，可以用p的后继s（树中大于x的最小的那个元素）代替p，然后使用情况1删除s（此时s一定满足情况1，可以画画看）。</p><p>基于以上逻辑，红黑树的节点删除函数<code>deleteEntry()</code>代码如下：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;红黑树entry删除函数deleteEntry()</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;deleteEntry(Entry&lt;K,V&gt;&nbsp;p)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;modCount++;<br />&nbsp;&nbsp;&nbsp;&nbsp;size--;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p.left&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>&nbsp;&amp;&amp;&nbsp;p.right&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;2.&nbsp;删除点p的左右子树都非空。</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;s&nbsp;=&nbsp;successor(p);<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;后继</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.key&nbsp;=&nbsp;s.key;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.value&nbsp;=&nbsp;s.value;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;=&nbsp;s;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;replacement&nbsp;=&nbsp;(p.left&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>&nbsp;?&nbsp;p.left&nbsp;:&nbsp;p.right);<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(replacement&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;1.&nbsp;删除点p只有一棵子树非空。</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;replacement.parent&nbsp;=&nbsp;p.parent;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p.parent&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;=&nbsp;replacement;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p&nbsp;==&nbsp;p.parent.left)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parent.left&nbsp;&nbsp;=&nbsp;replacement;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parent.right&nbsp;=&nbsp;replacement;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.left&nbsp;=&nbsp;p.right&nbsp;=&nbsp;p.parent&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p.color&nbsp;==&nbsp;BLACK)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fixAfterDeletion(replacement);<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;调整</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p.parent&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;1.&nbsp;删除点p的左右子树都为空</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p.color&nbsp;==&nbsp;BLACK)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fixAfterDeletion(p);<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;调整</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p.parent&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p&nbsp;==&nbsp;p.parent.left)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parent.left&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p&nbsp;==&nbsp;p.parent.right)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parent.right&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parent&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><div class="sourceCode"><pre class="sourceCode java"><br /></pre></div><p>上述代码中占据大量代码行的，是用来修改父子节点间引用关系的代码，其逻辑并不难理解。下面着重讲解删除后调整函数<code>fixAfterDeletion()</code>。首先请思考一下，删除了哪些点才会导致调整？<strong>只有删除点是BLACK的时候，才会触发调整函数</strong>，因为删除RED节点不会破坏红黑树的任何约束，而删除BLACK节点会破坏规则4。</p><p>跟上文中讲过的<code>fixAfterInsertion()</code>函数一样，这里也要分成若干种情况。记住，无论有多少情况，具体的调整操作只有两种：1.改变某些节点的颜色，2.对某些节点进行旋转。</p><p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160525072940334-1483504480.png" alt="TreeMap_fixAfterDeletion.png" width="800" height="1304" /></p><p>上述图解的总体思想是：将情况1首先转换成情况2，或者转换成情况3和情况4。当然，该图解并不意味着调整过程一定是从情况1开始。通过后续代码我们还会发现几个有趣的规则：a).如果是由情况1之后紧接着进入的情况2，那么情况2之后一定会退出循环（因为x为红色）；b).一旦进入情况3和情况4，一定会退出循环（因为x为root）。</p><p>删除后调整函数<code>fixAfterDeletion()</code>的具体代码如下，其中用到了上文中提到的<code>rotateLeft()</code>和<code>rotateRight()</code>函数。通过代码我们能够看到，情况3其实是落在情况4内的。情况5～情况8跟前四种情况是对称的，因此图解中并没有画出后四种情况，读者可以参考代码自行理解。<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;fixAfterDeletion(Entry&lt;K,V&gt;&nbsp;x)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(x&nbsp;!=&nbsp;root&nbsp;&amp;&amp;&nbsp;colorOf(x)&nbsp;==&nbsp;BLACK)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(x&nbsp;==&nbsp;leftOf(parentOf(x)))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;sib&nbsp;=&nbsp;rightOf(parentOf(x));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(colorOf(sib)&nbsp;==&nbsp;RED)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(sib,&nbsp;BLACK);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况1</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(x),&nbsp;RED);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况1</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rotateLeft(parentOf(x));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况1</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sib&nbsp;=&nbsp;rightOf(parentOf(x));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况1</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(colorOf(leftOf(sib))&nbsp;&nbsp;==&nbsp;BLACK&nbsp;&amp;&amp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;colorOf(rightOf(sib))&nbsp;==&nbsp;BLACK)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(sib,&nbsp;RED);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况2</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;parentOf(x);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况2</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(colorOf(rightOf(sib))&nbsp;==&nbsp;BLACK)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(leftOf(sib),&nbsp;BLACK);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况3</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(sib,&nbsp;RED);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况3</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rotateRight(sib);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况3</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sib&nbsp;=&nbsp;rightOf(parentOf(x));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况3</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(sib,&nbsp;colorOf(parentOf(x)));&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况4</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(x),&nbsp;BLACK);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况4</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(rightOf(sib),&nbsp;BLACK);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况4</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rotateLeft(parentOf(x));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况4</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;root;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况4</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;跟前四种情况对称</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;sib&nbsp;=&nbsp;leftOf(parentOf(x));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(colorOf(sib)&nbsp;==&nbsp;RED)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(sib,&nbsp;BLACK);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况5</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(x),&nbsp;RED);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况5</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rotateRight(parentOf(x));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况5</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sib&nbsp;=&nbsp;leftOf(parentOf(x));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况5</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(colorOf(rightOf(sib))&nbsp;==&nbsp;BLACK&nbsp;&amp;&amp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;colorOf(leftOf(sib))&nbsp;==&nbsp;BLACK)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(sib,&nbsp;RED);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况6</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;parentOf(x);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况6</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(colorOf(leftOf(sib))&nbsp;==&nbsp;BLACK)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(rightOf(sib),&nbsp;BLACK);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况7</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(sib,&nbsp;RED);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况7</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rotateLeft(sib);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况7</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sib&nbsp;=&nbsp;leftOf(parentOf(x));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况7</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(sib,&nbsp;colorOf(parentOf(x)));&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况8</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(x),&nbsp;BLACK);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况8</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(leftOf(sib),&nbsp;BLACK);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况8</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rotateRight(parentOf(x));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况8</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;root;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况8</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;setColor(x,&nbsp;BLACK);<br />}</div><div class="sourceCode"><pre class="sourceCode java"><br /></pre></div><h1 id="treeset">TreeSet</h1><p>前面已经说过<code>TreeSet</code>是对<code>TeeMap</code>的简单包装，对<code>TreeSet</code>的函数调用都会转换成合适的<code>TeeMap</code>方法，因此<code>TreeSet</code>的实现非常简单。这里不再赘述。<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;TreeSet是对TreeMap的简单包装</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;TreeSet&lt;E&gt;&nbsp;<span style="color: #0000FF; ">extends</span>&nbsp;AbstractSet&lt;E&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">implements</span>&nbsp;NavigableSet&lt;E&gt;,&nbsp;Cloneable,&nbsp;java.io.Serializable<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">transient</span>&nbsp;NavigableMap&lt;E,Object&gt;&nbsp;m;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;Dummy&nbsp;value&nbsp;to&nbsp;associate&nbsp;with&nbsp;an&nbsp;Object&nbsp;in&nbsp;the&nbsp;backing&nbsp;Map</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Object&nbsp;PRESENT&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Object();<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;TreeSet()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.m&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;TreeMap&lt;E,Object&gt;();<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;TreeSet里面有一个TreeMap</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;add(E&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;m.put(e,&nbsp;PRESENT)==<span style="color: #0000FF; ">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />}</div><div class="sourceCode"><pre class="sourceCode java"><br /></pre></div></div><img src ="http://www.blogjava.net/CarpenterLee/aggbug/430645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/CarpenterLee/" target="_blank">CarpenterLee</a> 2016-05-25 16:48 <a href="http://www.blogjava.net/CarpenterLee/archive/2016/05/25/430645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>史上最清晰的红黑树讲解（上）</title><link>http://www.blogjava.net/CarpenterLee/archive/2016/05/18/430564.html</link><dc:creator>CarpenterLee</dc:creator><author>CarpenterLee</author><pubDate>Tue, 17 May 2016 23:57:00 GMT</pubDate><guid>http://www.blogjava.net/CarpenterLee/archive/2016/05/18/430564.html</guid><wfw:comment>http://www.blogjava.net/CarpenterLee/comments/430564.html</wfw:comment><comments>http://www.blogjava.net/CarpenterLee/archive/2016/05/18/430564.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/CarpenterLee/comments/commentRss/430564.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/CarpenterLee/services/trackbacks/430564.html</trackback:ping><description><![CDATA[<div id="cnblogs_post_body" class="cnblogs-markdown"><p><a href="https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/5-TreeSet%20and%20TreeMap.md">本文github地址</a></p><p>本文以Java TreeMap为例，从源代码层面，结合详细的图解，剥茧抽丝地讲解红黑树（Red-Black tree）的插入，删除以及由此产生的调整过程。</p><h1 id="总体介绍">总体介绍</h1><p>Java <em>TreeMap</em>实现了<em>SortedMap</em>接口，也就是说会按照<code>key</code>的大小顺序对<em>Map</em>中的元素进行排序，<code>key</code>大小的评判可以通过其本身的自然顺序（natural ordering），也可以通过构造时传入的比较器（Comparator）。</p><p><strong><em>TreeMap</em>底层通过红黑树（Red-Black tree）实现</strong>，也就意味着<code>containsKey()</code>, <code>get()</code>, <code>put()</code>, <code>remove()</code>都有着<code>log(n)</code>的时间复杂度。其具体算法实现参照了《算法导论》。</p><p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160517211933779-124491145.png" alt="TreeMap_base.png" /></p><p>出于性能原因，<em>TreeMap</em>是非同步的（not synchronized），如果需要在多线程环境使用，需要程序员手动同步；或者通过如下方式将<em>TreeMap</em>包装成（wrapped）同步的：</p><p><code>SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));</code></p><p><strong>红黑树是一种近似平衡的二叉查找树，它能够确保任何一个节点的左右子树的高度差不会超过二者中较低那个的一陪</strong>。具体来说，红黑树是满足如下条件的二叉查找树（binary search tree）：</p><ol><li>每个节点要么是红色，要么是黑色。</li><li>根节点必须是黑色</li><li>红色节点不能连续（也即是，红色节点的孩子和父亲都不能是红色）。</li><li>对于每个节点，从该点至<code>null</code>（树尾端）的任何路径，都含有相同个数的黑色节点。</li></ol><p>在树的结构发生改变时（插入或者删除操作），往往会破坏上述条件3或条件4，需要通过调整使得查找树重新满足红黑树的条件。</p><h1 id="预备知识">预备知识</h1><p>前文说到当查找树的结构发生改变时，红黑树的条件可能被破坏，需要通过调整使得查找树重新满足红黑树的条件。调整可以分为两类：一类是颜色调整，即改变某个节点的颜色；另一类是结构调整，集改变检索树的结构关系。结构调整过程包含两个基本操作：<strong>左旋（Rotate Left），右旋（RotateRight）</strong>。</p><h2 id="左旋">左旋</h2><p>左旋的过程是将<code>x</code>的右子树绕<code>x</code>逆时针旋转，使得<code>x</code>的右子树成为<code>x</code>的父亲，同时修改相关节点的引用。旋转之后，二叉查找树的属性仍然满足。</p><p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160517212009529-1958413310.png" alt="TreeMap_rotateLeft.png" /></p><p><em>TreeMap</em>中左旋代码如下：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">Rotate&nbsp;Left</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;rotateLeft(Entry&lt;K,V&gt;&nbsp;p)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;r&nbsp;=&nbsp;p.right;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.right&nbsp;=&nbsp;r.left;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(r.left&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r.left.parent&nbsp;=&nbsp;p;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r.parent&nbsp;=&nbsp;p.parent;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p.parent&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;=&nbsp;r;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p.parent.left&nbsp;==&nbsp;p)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parent.left&nbsp;=&nbsp;r;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parent.right&nbsp;=&nbsp;r;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r.left&nbsp;=&nbsp;p;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parent&nbsp;=&nbsp;r;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><div class="sourceCode"><pre class="sourceCode java"><br /></pre></div><h2 id="右旋">右旋</h2><p>右旋的过程是将<code>x</code>的左子树绕<code>x</code>顺时针旋转，使得<code>x</code>的左子树成为<code>x</code>的父亲，同时修改相关节点的引用。旋转之后，二叉查找树的属性仍然满足。</p><p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160517212020498-954534792.png" alt="TreeMap_rotateRight.png" /></p><p><em>TreeMap</em>中右旋代码如下：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">Rotate&nbsp;Right</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;rotateRight(Entry&lt;K,V&gt;&nbsp;p)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;l&nbsp;=&nbsp;p.left;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.left&nbsp;=&nbsp;l.right;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(l.right&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;l.right.parent&nbsp;=&nbsp;p;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;l.parent&nbsp;=&nbsp;p.parent;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p.parent&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;=&nbsp;l;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(p.parent.right&nbsp;==&nbsp;p)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parent.right&nbsp;=&nbsp;l;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;p.parent.left&nbsp;=&nbsp;l;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;l.right&nbsp;=&nbsp;p;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p.parent&nbsp;=&nbsp;l;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><div class="sourceCode"><pre class="sourceCode java"><br /></pre></div><h1 id="方法剖析">方法剖析</h1><h2 id="get">get()</h2><p><code>get(Object key)</code>方法根据指定的<code>key</code>值返回对应的<code>value</code>，该方法调用了<code>getEntry(Object key)</code>得到相应的<code>entry</code>，然后返回<code>entry.value</code>。因此<code>getEntry()</code>是算法的核心。算法思想是根据<code>key</code>的自然顺序（或者比较器顺序）对二叉查找树进行查找，直到找到满足<code>k.compareTo(p.key) == 0</code>的<code>entry</code>。</p><p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160517211944357-1810109113.png" alt="TreeMap_getEntry.png" /></p><p>具体代码如下：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">getEntry()方法</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">final</span>&nbsp;Entry&lt;K,V&gt;&nbsp;getEntry(Object&nbsp;key)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(key&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<span style="color: #008000; ">//</span><span style="color: #008000; ">不允许key值为null</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">throw</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;NullPointerException();<br />&nbsp;&nbsp;&nbsp;&nbsp;Comparable&lt;?&nbsp;<span style="color: #0000FF; ">super</span>&nbsp;K&gt;&nbsp;k&nbsp;=&nbsp;(Comparable&lt;?&nbsp;<span style="color: #0000FF; ">super</span>&nbsp;K&gt;)&nbsp;key;<span style="color: #008000; ">//</span><span style="color: #008000; ">使用元素的自然顺序</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;p&nbsp;=&nbsp;root;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(p&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;cmp&nbsp;=&nbsp;k.compareTo(p.key);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(cmp&nbsp;&lt;&nbsp;0)<span style="color: #008000; ">//</span><span style="color: #008000; ">向左找</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;=&nbsp;p.left;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(cmp&nbsp;&gt;&nbsp;0)<span style="color: #008000; ">//</span><span style="color: #008000; ">向右找</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;=&nbsp;p.right;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;p;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">null</span>;<br />}</div><div class="sourceCode"><pre class="sourceCode java"><br /></pre></div><h2 id="put">put()</h2><p><code>put(K key, V value)</code>方法是将指定的<code>key</code>, <code>value</code>对添加到<code>map</code>里。该方法首先会对<code>map</code>做一次查找，看是否包含该元组，如果已经包含则直接返回，查找过程类似于<code>getEntry()</code>方法；如果没有找到则会在红黑树中插入新的<code>entry</code>，如果插入之后破坏了红黑树的约束，还需要进行调整（旋转，改变某些节点的颜色）。<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;V&nbsp;put(K&nbsp;key,&nbsp;V&nbsp;value)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;cmp;<br />&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;parent;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(key&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">throw</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;NullPointerException();<br />&nbsp;&nbsp;&nbsp;&nbsp;Comparable&lt;?&nbsp;<span style="color: #0000FF; ">super</span>&nbsp;K&gt;&nbsp;k&nbsp;=&nbsp;(Comparable&lt;?&nbsp;<span style="color: #0000FF; ">super</span>&nbsp;K&gt;)&nbsp;key;<span style="color: #008000; ">//</span><span style="color: #008000; ">使用元素的自然顺序</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">do</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parent&nbsp;=&nbsp;t;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp&nbsp;=&nbsp;k.compareTo(t.key);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(cmp&nbsp;&lt;&nbsp;0)&nbsp;t&nbsp;=&nbsp;t.left;<span style="color: #008000; ">//</span><span style="color: #008000; ">向左找</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(cmp&nbsp;&gt;&nbsp;0)&nbsp;t&nbsp;=&nbsp;t.right;<span style="color: #008000; ">//</span><span style="color: #008000; ">向右找</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;t.setValue(value);<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(t&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>);<br />&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;e&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Entry&lt;&gt;(key,&nbsp;value,&nbsp;parent);<span style="color: #008000; ">//</span><span style="color: #008000; ">创建并插入新的entry</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(cmp&nbsp;&lt;&nbsp;0)&nbsp;parent.left&nbsp;=&nbsp;e;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;parent.right&nbsp;=&nbsp;e;<br />&nbsp;&nbsp;&nbsp;&nbsp;fixAfterInsertion(e);<span style="color: #008000; ">//</span><span style="color: #008000; ">调整</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;size++;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">null</span>;<br />}</div><div class="sourceCode"><pre class="sourceCode java"><br /></pre></div><p>上述代码的插入部分并不难理解：首先在红黑树上找到合适的位置，然后创建新的<code>entry</code>并插入（当然，新插入的节点一定是树的叶子）。难点是调整函数<code>fixAfterInsertion()</code>，前面已经说过，调整往往需要1.改变某些节点的颜色，2.对某些节点进行旋转。</p><p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160517212000341-1761362961.png" alt="TreeMap_put.png" /></p><p>调整函数<code>fixAfterInsertion()</code>的具体代码如下，其中用到了上文中提到的<code>rotateLeft()</code>和<code>rotateRight()</code>函数。通过代码我们能够看到，情况2其实是落在情况3内的。情况4～情况6跟前三种情况是对称的，因此图解中并没有画出后三种情况，读者可以参考代码自行理解。<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">红黑树调整函数fixAfterInsertion()</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;fixAfterInsertion(Entry&lt;K,V&gt;&nbsp;x)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;x.color&nbsp;=&nbsp;RED;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(x&nbsp;!=&nbsp;<span style="color: #0000FF; ">null</span>&nbsp;&amp;&amp;&nbsp;x&nbsp;!=&nbsp;root&nbsp;&amp;&amp;&nbsp;x.parent.color&nbsp;==&nbsp;RED)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(parentOf(x)&nbsp;==&nbsp;leftOf(parentOf(parentOf(x))))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;y&nbsp;=&nbsp;rightOf(parentOf(parentOf(x)));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(colorOf(y)&nbsp;==&nbsp;RED) {<span style="color: #008000; font-family: 'Courier New', sans-serif; font-size: 12px; line-height: 18px; white-space: pre-wrap; background-color: #f5f5f5;">//如果y为null，则视为BLACK</span><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setColor(parentOf(x),&nbsp;BLACK); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况1</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(y,&nbsp;BLACK); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况1</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(parentOf(x)),&nbsp;RED); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况1</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;parentOf(parentOf(x)); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况1</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(x&nbsp;==&nbsp;rightOf(parentOf(x)))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;parentOf(x); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况2</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rotateLeft(x); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000;">//</span><span style="color: #008000; ">&nbsp;情况2</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(x),&nbsp;BLACK); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况3</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(parentOf(x)),&nbsp;RED); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况3</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rotateRight(parentOf(parentOf(x))); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况3</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Entry&lt;K,V&gt;&nbsp;y&nbsp;=&nbsp;leftOf(parentOf(parentOf(x)));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(colorOf(y)&nbsp;==&nbsp;RED)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(x),&nbsp;BLACK); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况4</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(y,&nbsp;BLACK); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况4</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(parentOf(x)),&nbsp;RED); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况4</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;parentOf(parentOf(x)); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况4</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(x&nbsp;==&nbsp;leftOf(parentOf(x)))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;parentOf(x); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况5</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rotateRight(x); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况5</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(x),&nbsp;BLACK); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况6</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setColor(parentOf(parentOf(x)),&nbsp;RED); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况6</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rotateLeft(parentOf(parentOf(x))); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;情况6</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;root.color&nbsp;=&nbsp;BLACK;<br />}</div><div class="sourceCode"><pre class="sourceCode java"><br /></pre></div><h2 id="remove">remove()</h2><p><code>remove(Object key)</code>的作用是删除<code>key</code>值对应的<code>entry</code>，该方法首先通过上文中提到的<code>getEntry(Object key)</code>方法找到<code>key</code>值对应的<code>entry</code>，然后调用<code>deleteEntry(Entry&lt;K,V&gt; entry)</code>删除对应的<code>entry</code>。由于删除操作会改变红黑树的结构，有可能破坏红黑树的约束，因此有可能要进行调整。</p><p><strong>有关<code>remove()</code>的具体讲解将放到下一篇博文当中，敬请期待！</strong></p></div><img src ="http://www.blogjava.net/CarpenterLee/aggbug/430564.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/CarpenterLee/" target="_blank">CarpenterLee</a> 2016-05-18 07:57 <a href="http://www.blogjava.net/CarpenterLee/archive/2016/05/18/430564.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java PriorityQueue源码剖析</title><link>http://www.blogjava.net/CarpenterLee/archive/2016/05/12/430473.html</link><dc:creator>CarpenterLee</dc:creator><author>CarpenterLee</author><pubDate>Thu, 12 May 2016 13:22:00 GMT</pubDate><guid>http://www.blogjava.net/CarpenterLee/archive/2016/05/12/430473.html</guid><wfw:comment>http://www.blogjava.net/CarpenterLee/comments/430473.html</wfw:comment><comments>http://www.blogjava.net/CarpenterLee/archive/2016/05/12/430473.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/CarpenterLee/comments/commentRss/430473.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/CarpenterLee/services/trackbacks/430473.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Java中PriorityQueue通过二叉小顶堆实现，可以用一棵完全二叉树表示。本文从Queue接口函数出发，结合生动的图解，深入浅出地分析PriorityQueue每个操作的具体过程和开销，将有助于您对该容器建立清晰明了的认识。&nbsp;&nbsp;<a href='http://www.blogjava.net/CarpenterLee/archive/2016/05/12/430473.html'>阅读全文</a><img src ="http://www.blogjava.net/CarpenterLee/aggbug/430473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/CarpenterLee/" target="_blank">CarpenterLee</a> 2016-05-12 21:22 <a href="http://www.blogjava.net/CarpenterLee/archive/2016/05/12/430473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为什么你的博客不够火？</title><link>http://www.blogjava.net/CarpenterLee/archive/2016/05/11/430433.html</link><dc:creator>CarpenterLee</dc:creator><author>CarpenterLee</author><pubDate>Wed, 11 May 2016 01:02:00 GMT</pubDate><guid>http://www.blogjava.net/CarpenterLee/archive/2016/05/11/430433.html</guid><wfw:comment>http://www.blogjava.net/CarpenterLee/comments/430433.html</wfw:comment><comments>http://www.blogjava.net/CarpenterLee/archive/2016/05/11/430433.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.blogjava.net/CarpenterLee/comments/commentRss/430433.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/CarpenterLee/services/trackbacks/430433.html</trackback:ping><description><![CDATA[<h1 class="postTitle"><br />
</h1>
<div id="cnblogs_post_body" class="cnblogs-markdown">
<h1 id="cnblog首页博客热度分析">CNBlog首页博客热度分析</h1>
<p><a href="https://github.com/CarpenterLee/CNBlogHotAnalyze">本文github地址</a></p>
<h1 id="前言">前言</h1>
<p>每个博客园的园友或许都会有这种经历：自己辛辛苦苦，认认真真的写了篇博客，然后满心欢喜的发到了博客园首页，当你以为大功告成坐等点击量暴表的时候，却发现自己的博文根本无人问津。那将是何等的痛苦:(</p>
<p>不要再自我怀疑，不要再自怨自艾，博客不火，不一定是博文内容不够严谨深入，也不一定是你能力不足，而可能仅仅是因为你选择了错误的发表时机。</p>
<p>本文基于博客园近3个月4000篇首页博文，运用大数据分析，机器学习，文本挖掘等先进技术，<strong>深入而细致的剖析决定博客热度的若干因素，让您从此也能写出精湛的技术博客，成为博客园的技术达人（做梦到此结束...）。</strong></p>
<h1 id="技术实现">技术实现</h1>
<p>经分析，博客园首页网页结构比较简洁，通过爬虫抓取<a href="http://www.cnblogs.com/sitehome/p/3">http://www.cnblogs.com/sitehome/p/your_page_num</a> 连接下的内容，即可获取所有首页博文。本文采用的是<a href="https://jsoup.org/">jsoup</a>这个Java HTML Parser进行的网页抓取。博客园页码只支持到200，每页20篇，也就是最多能够抓取4000篇首页博客。对数据进行清洗后存储到文件，供下一步分析。</p>
<p>由于数据量并不大，分析数据采用的是excel表格。不要觉得low，用表格来处理小规模数据，效果不亚于数据库。</p>
<h1 id="分析结果">分析结果</h1>
<h2 id="博友们一天之内喜欢什么时候发博客">博友们一天之内喜欢什么时候发博客？</h2>
<h2 id="哪个时间段发的博客更容易火">哪个时间段发的博客更容易火？</h2>
<p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160510224746390-1420868655.png" alt="HotOfHours.png" /></p>
<p>我们对一天中不同时间段发表的博客进行统计，然后计算每个小时内的博客发表量，以及当前这个小时每篇博客的平均热度。这里的热度是用来衡量一篇博文受欢迎程度的综合指标，计算公式为：</p>
<p><code>hot=(recommend*10+comment*5+view)</code></p>
<p>为避免离群点，当hot值超过1600时则按1600处理。上图中标注的热度（红色线）为对文章热度求平均之后，然后做归一化<code>(avg_hot/800*100%)</code>之后的结果。</p>
<p>从上图可以明显看出，<strong>一天之内有三个时间段大家比较爱发博客</strong>，分别是10:00左右，16:00左右和22:00左右，这分别对应的是上午上班时间，下午上班时间，和晚上加班时间。<strong>一天内也有三个时间段大家不怎么爱发博客</strong>，分别是1:00~7:00，12:00左右，19:00左右，分别对应大家的睡觉时间，午饭时间和下班时间。</p>
<p>什么时候发的博客更容易火呢？抛开凌晨那段时间不提（因为博客量太少），上图可以看出，早上8:00左右发的博客热度最高，中午12:00左右和晚上22:00左右也是个热度小高峰。</p>
<p>对比上图中的蓝线和红线，我们发现博客发表高峰和访问高峰（热度评估主要基于访问量，所以热度表示了访问量的趋势）并不总是成比例。具体表现如下：</p>
<blockquote>
<ol>
     <li>早上8:00是一天中访问量最高的时候，但博客发表并不是很多（上班路上大家刷刷博客？）</li>
     <li>上午10:00左右是博客发表的高峰，但访问量却呈下降趋势（忙着写自己的博客而忘记看别人的博客）</li>
     <li>中午12:00左右访问量很高，但博客发表量却出奇的低（吃饭的时候不写博客，倒是可以手机刷刷博客）</li>
</ol>
</blockquote>
<h2 id="大家一周之内喜欢在哪一天发博客">大家一周之内喜欢在哪一天发博客？</h2>
<h2 id="一周之内哪一天发的博客更容易火">一周之内哪一天发的博客更容易火？</h2>
<p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160510224753093-1106735401.png" alt="HotOfDays.png" /></p>
<p>我们对一周中不同天发表的博客进行统计，然后计算每天的博客发表量，以及当天每篇博客的平均热度。</p>
<p>通过上图可以看出：</p>
<blockquote>
<ol>
     <li>星期一和星期二是博客发表的热潮（上班前两天不但工作积极，写博客也很积极）</li>
     <li>之后一直下降，到周六达到最低谷（终于盼来周末，谁还写博客！）。</li>
     <li>博客热度跟发表量基本吻合，可见工作日大家不但工作热情高，写博客和读博客的热情都不低。</li>
     <li>到了周末，写博客的人少，看博客的人更少！</li>
     <li>周四博客阅读量出现了回升，你可以帮忙想想是为什么。</li>
</ol>
</blockquote>
<p>上图意味着，<strong>周末还是老老实实的出去玩吧，即使写了博客也不会有人看的</strong>。特别是周六，千万不要在周六发表技术博客，切记切记！</p>
<h1 id="总结">总结</h1>
<p>经过以上分析，我们得出结论：为了避免吃力不讨好的情况，发表博客一定要认准时机。</p>
<ol>
     <li><strong>博客想要火，就不能睡懒觉，因为你要在8:00钟左右发表博客。</strong></li>
     <li><strong>更不能吃午饭，因为你还要在12:00左右发表博客。</strong></li>
     <li>当然，为了犒劳以下忙碌一周的你，<strong>周末切记不要苦逼的写博客，因为即使写得再认真也不会有人看。</strong></li>
     <li><strong>周一，周二以及周四，才是您发表博客的黄道吉日。</strong></li>
</ol>
<p>以上四项基本原则，一定要牢记于心，切记不要轻易违背。否则没有点击量，你的博客还不如写道日记本里。</p>
<h1 id="未来的工作">未来的工作</h1>
<p>博客热度不仅跟发表时间有关，当然也跟博客内容，以及博主的个人影响力等诸多因素相关。希望各位博友能够加入更多分析。</p>
<p><strong>本文用到的所有代码和数据，都已经放到了<a href="https://github.com/CarpenterLee/CNBlogHotAnalyze">博主github</a>上，欢迎各位博友切磋。</strong></p>
</div>
<img src ="http://www.blogjava.net/CarpenterLee/aggbug/430433.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/CarpenterLee/" target="_blank">CarpenterLee</a> 2016-05-11 09:02 <a href="http://www.blogjava.net/CarpenterLee/archive/2016/05/11/430433.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java ArrayDeque源码剖析</title><link>http://www.blogjava.net/CarpenterLee/archive/2016/05/07/430396.html</link><dc:creator>CarpenterLee</dc:creator><author>CarpenterLee</author><pubDate>Sat, 07 May 2016 10:30:00 GMT</pubDate><guid>http://www.blogjava.net/CarpenterLee/archive/2016/05/07/430396.html</guid><wfw:comment>http://www.blogjava.net/CarpenterLee/comments/430396.html</wfw:comment><comments>http://www.blogjava.net/CarpenterLee/archive/2016/05/07/430396.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/CarpenterLee/comments/commentRss/430396.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/CarpenterLee/services/trackbacks/430396.html</trackback:ping><description><![CDATA[<div id="cnblogs_post_body" class="cnblogs-markdown">
<h1 id="arraydeque">ArrayDeque</h1>
<p><a href="https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/4-Stack%20and%20Queue.md">本文github地址</a></p>
<h1 id="前言">前言</h1>
<p>Java里有一个叫做<em>Stack</em>的类，却没有叫做<em>Queue</em>的类（它是个接口名字）。当需要使用栈时，Java已不推荐使用<em>Stack</em>，而是推荐使用更高效的<em>ArrayDeque</em>；既然<em>Queue</em>只是一个接口，当需要使用队列时也就首选<em>ArrayDeque</em>了（次选是<em>LinkedList</em>）。</p>
<h1 id="总体介绍">总体介绍</h1>
<p>要讲栈和队列，首先要讲<em>Deque</em>接口。<em>Deque</em>的含义是&#8220;double ended queue&#8221;，即双端队列，它既可以当作栈使用，也可以当作队列使用。下表列出了<em>Deque</em>与<em>Queue</em>相对应的接口：</p>
<table>
     <thead>
         <tr class="header">
             <th>Queue Method</th><th>Equivalent Deque Method</th><th>说明</th>
         </tr>
     </thead>
     <tbody>
         <tr class="odd">
             <td><code>add(e)</code></td>
             <td><code>addLast(e)</code></td>
             <td>向队尾插入元素，失败则抛出异常</td>
         </tr>
         <tr class="even">
             <td><code>offer(e)</code></td>
             <td><code>offerLast(e)</code></td>
             <td>向队尾插入元素，失败则返回<code>false</code></td>
         </tr>
         <tr class="odd">
             <td><code>remove()</code></td>
             <td><code>removeFirst()</code></td>
             <td>获取并删除队首元素，失败则抛出异常</td>
         </tr>
         <tr class="even">
             <td><code>poll()</code></td>
             <td><code>pollFirst()</code></td>
             <td>获取并删除队首元素，失败则返回<code>null</code></td>
         </tr>
         <tr class="odd">
             <td><code>element()</code></td>
             <td><code>getFirst()</code></td>
             <td>获取但不删除队首元素，失败则抛出异常</td>
         </tr>
         <tr class="even">
             <td><code>peek()</code></td>
             <td><code>peekFirst()</code></td>
             <td>获取但不删除队首元素，失败则返回<code>null</code></td>
         </tr>
     </tbody>
</table>
<p>下表列出了<em>Deque</em>与<em>Stack</em>对应的接口：</p>
<table>
     <thead>
         <tr class="header">
             <th>Stack Method</th><th>Equivalent Deque Method</th><th>说明</th>
         </tr>
     </thead>
     <tbody>
         <tr class="odd">
             <td><code>push(e)</code></td>
             <td><code>addFirst(e)</code></td>
             <td>向栈顶插入元素，失败则抛出异常</td>
         </tr>
         <tr class="even">
             <td>无</td>
             <td><code>offerFirst(e)</code></td>
             <td>向栈顶插入元素，失败则返回<code>false</code></td>
         </tr>
         <tr class="odd">
             <td><code>pop()</code></td>
             <td><code>removeFirst()</code></td>
             <td>获取并删除栈顶元素，失败则抛出异常</td>
         </tr>
         <tr class="even">
             <td>无</td>
             <td><code>pollFirst()</code></td>
             <td>获取并删除栈顶元素，失败则返回<code>null</code></td>
         </tr>
         <tr class="odd">
             <td><code>peek()</code></td>
             <td><code>peekFirst()</code></td>
             <td>获取但不删除栈顶元素，失败则抛出异常</td>
         </tr>
         <tr class="even">
             <td>无</td>
             <td><code>peekFirst()</code></td>
             <td>获取但不删除栈顶元素，失败则返回<code>null</code></td>
         </tr>
     </tbody>
</table>
<p>上面两个表共定义了<em>Deque</em>的12个接口。添加，删除，取值都有两套接口，它们功能相同，区别是对失败情况的处理不同。<strong>一套接口遇到失败就会抛出异常，另一套遇到失败会返回特殊值（<code>false</code>或<code>null</code>）</strong>。除非某种实现对容量有限制，大多数情况下，添加操作是不会失败的。<strong>虽然<em>Deque</em>的接口有12个之多，但无非就是对容器的两端进行操作，或添加，或删除，或查看</strong>。明白了这一点讲解起来就会非常简单。</p>
<p><em>ArrayDeque</em>和<em>LinkedList</em>是<em>Deque</em>的两个通用实现，由于官方更推荐使用<em>AarryDeque</em>用作栈和队列，加之上一篇已经讲解过<em>LinkedList</em>，本文将着重讲解<em>ArrayDeque</em>的具体实现。</p>
<p>从名字可以看出<em>ArrayDeque</em>底层通过数组实现，为了满足可以同时在数组两端插入或删除元素的需求，该数组还必须是循环的，即<strong>循环数组（circular array）</strong>，也就是说数组的任何一点都可能被看作起点或者终点。<em>ArrayDeque</em>是非线程安全的（not thread-safe），当多个线程同时使用的时候，需要程序员手动同步；另外，该容器不允许放入<code>null</code>元素。</p>
<p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160507172937875-1444735637.png" alt="ArrayDeque_base.png" /></p>
<p>上图中我们看到，<strong><code>head</code>指向首端第一个有效元素，<code>tail</code>指向尾端第一个可以插入元素的空位</strong>。因为是循环数组，所以<code>head</code>不一定总等于0，<code>tail</code>也不一定总是比<code>head</code>大。</p>
<h1 id="方法剖析">方法剖析</h1>
<h2 id="addfirst">addFirst()</h2>
<p><code>addFirst(E e)</code>的作用是在<em>Deque</em>的首端插入元素，也就是在<code>head</code>的前面插入元素，在空间足够且下标没有越界的情况下，只需要将<code>elements[--head] = e</code>即可。</p>
<p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160507172943265-2092213314.png" alt="ArrayDeque_addFirst.png" /></p>
<p>实际需要考虑：1.空间是否够用，以及2.下标是否越界的问题。上图中，如果<code>head</code>为<code>0</code>之后接着调用<code>addFirst()</code>，虽然空余空间还够用，但<code>head</code>为<code>-1</code>，下标越界了。下列代码很好的解决了这两个问题。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008000; ">//</span><span style="color: #008000; ">addFirst(E&nbsp;e)</span><span style="color: #008000; "><br />
</span><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;addFirst(E&nbsp;e)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(e&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<span style="color: #008000; ">//</span><span style="color: #008000; ">不允许放入null</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">throw</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;NullPointerException();<br />
&nbsp;&nbsp;&nbsp;&nbsp;elements[head&nbsp;=&nbsp;(head&nbsp;-&nbsp;1)&nbsp;&amp;&nbsp;(elements.length&nbsp;-&nbsp;1)]&nbsp;=&nbsp;e;<span style="color: #008000; ">//</span><span style="color: #008000; ">2.下标是否越界</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(head&nbsp;==&nbsp;tail)<span style="color: #008000; ">//</span><span style="color: #008000; ">1.空间是否够用</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;doubleCapacity();<span style="color: #008000; ">//</span><span style="color: #008000; ">扩容</span><span style="color: #008000; "><br />
</span>}</div>
<div class="sourceCode">
<pre class="sourceCode java"><span style="font-family: verdana, 'courier new';">上述代码我们看到，</span><strong style="font-family: verdana, 'courier new';">空间问题是在插入之后解决的</strong><span style="font-family: verdana, 'courier new';">，因为</span><code>tail</code><span style="font-family: verdana, 'courier new';">总是指向下一个可插入的空位，也就意味着</span><code>elements</code><span style="font-family: verdana, 'courier new';">数组至少有一个空位，所以插入元素的时候不用考虑空间问题。</span></pre>
</div>
<p>下标越界的处理解决起来非常简单，<code>head = (head - 1) &amp; (elements.length - 1)</code>就可以了，<strong>这段代码相当于取余，同时解决了<code>head</code>为负值的情况</strong>。因为<code>elements.length</code>必需是<code>2</code>的指数倍，<code>elements - 1</code>就是二进制低位全<code>1</code>，跟<code>head - 1</code>相与之后就起到了取模的作用，如果<code>head - 1</code>为负数（其实只可能是-1），则相当于对其取相对于<code>elements.length</code>的补码。</p>
<p>下面再说说扩容函数<code>doubleCapacity()</code>，其逻辑是申请一个更大的数组（原数组的两倍），然后将原数组复制过去。过程如下图所示：</p>
<p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160507172951125-776162110.png" alt="ArrayDeque_doubleCapacity.png" width="800" height="293" /></p>
<p>图中我们看到，复制分两次进行，第一次复制<code>head</code>右边的元素，第二次复制<code>head</code>左边的元素。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008000; ">//</span><span style="color: #008000; ">doubleCapacity()</span><span style="color: #008000; "><br />
</span><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;doubleCapacity()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">assert</span>&nbsp;head&nbsp;==&nbsp;tail;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;p&nbsp;=&nbsp;head;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;n&nbsp;=&nbsp;elements.length;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;r&nbsp;=&nbsp;n&nbsp;-&nbsp;p;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;head右边元素的个数</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;newCapacity&nbsp;=&nbsp;n&nbsp;&lt;&lt;&nbsp;1;<span style="color: #008000; ">//</span><span style="color: #008000; ">原空间的2倍</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(newCapacity&nbsp;&lt;&nbsp;0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">throw</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;IllegalStateException("Sorry,&nbsp;deque&nbsp;too&nbsp;big");<br />
&nbsp;&nbsp;&nbsp;&nbsp;Object[]&nbsp;a&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Object[newCapacity];<br />
&nbsp;&nbsp;&nbsp;&nbsp;System.arraycopy(elements,&nbsp;p,&nbsp;a,&nbsp;0,&nbsp;r);<span style="color: #008000; ">//</span><span style="color: #008000; ">复制右半部分，对应上图中绿色部分</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;System.arraycopy(elements,&nbsp;0,&nbsp;a,&nbsp;r,&nbsp;p);<span style="color: #008000; ">//</span><span style="color: #008000; ">复制左半部分，对应上图中灰色部分</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;elements&nbsp;=&nbsp;(E[])a;<br />
&nbsp;&nbsp;&nbsp;&nbsp;head&nbsp;=&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;tail&nbsp;=&nbsp;n;<br />
}</div>
<p><br />
</p>
<h2 id="addlast">addLast()</h2>
<p><code>addLast(E e)</code>的作用是在<em>Deque</em>的尾端插入元素，也就是在<code>tail</code>的位置插入元素，由于<code>tail</code>总是指向下一个可以插入的空位，因此只需要<code>elements[tail] = e;</code>即可。插入完成后再检查空间，如果空间已经用光，则调用<code>doubleCapacity()</code>进行扩容。</p>
<p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160507172955312-946261107.png" alt="ArrayDeque_addLast.png" /><br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;addLast(E&nbsp;e)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(e&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<span style="color: #008000; ">//</span><span style="color: #008000; ">不允许放入null</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">throw</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;NullPointerException();<br />
&nbsp;&nbsp;&nbsp;&nbsp;elements[tail]&nbsp;=&nbsp;e;<span style="color: #008000; ">//</span><span style="color: #008000; ">赋值</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(&nbsp;(tail&nbsp;=&nbsp;(tail&nbsp;+&nbsp;1)&nbsp;&amp;&nbsp;(elements.length&nbsp;-&nbsp;1))&nbsp;==&nbsp;head)<span style="color: #008000; ">//</span><span style="color: #008000; ">下标越界处理</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;doubleCapacity();<span style="color: #008000; ">//</span><span style="color: #008000; ">扩容</span><span style="color: #008000; "><br />
</span>}</div>
<div class="sourceCode">
<pre class="sourceCode java"><span style="font-family: verdana, 'courier new';">下标越界处理方式</span><code>addFirt()</code><span style="font-family: verdana, 'courier new';">中已经讲过，不再赘述。</span></pre>
</div>
<h2 id="pollfirst">pollFirst()</h2>
<p><code>pollFirst()</code>的作用是删除并返回<em>Deque</em>首端元素，也即是<code>head</code>位置处的元素。如果容器不空，只需要直接返回<code>elements[head]</code>即可，当然还需要处理下标的问题。由于<code>ArrayDeque</code>中不允许放入<code>null</code>，当<code>elements[head] == null</code>时，意味着容器为空。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span>&nbsp;E&nbsp;pollFirst()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;E&nbsp;result&nbsp;=&nbsp;elements[head];<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(result&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<span style="color: #008000; ">//</span><span style="color: #008000; ">null值意味着deque为空</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">null</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;elements[h]&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<span style="color: #008000; ">//</span><span style="color: #008000; ">let&nbsp;GC&nbsp;work</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;head&nbsp;=&nbsp;(head&nbsp;+&nbsp;1)&nbsp;&amp;&nbsp;(elements.length&nbsp;-&nbsp;1);<span style="color: #008000; ">//</span><span style="color: #008000; ">下标越界处理</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;result;<br />
}</div>
<div class="sourceCode">
<pre class="sourceCode java"><br />
</pre>
</div>
<h2 id="polllast">pollLast()</h2>
<p><code>pollLast()</code>的作用是删除并返回<em>Deque</em>尾端元素，也即是<code>tail</code>位置前面的那个元素。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span>&nbsp;E&nbsp;pollLast()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;t&nbsp;=&nbsp;(tail&nbsp;-&nbsp;1)&nbsp;&amp;&nbsp;(elements.length&nbsp;-&nbsp;1);<span style="color: #008000; ">//</span><span style="color: #008000; ">tail的上一个位置是最后一个元素</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;E&nbsp;result&nbsp;=&nbsp;elements[t];<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(result&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<span style="color: #008000; ">//</span><span style="color: #008000; ">null值意味着deque为空</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">null</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;elements[t]&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<span style="color: #008000; ">//</span><span style="color: #008000; ">let&nbsp;GC&nbsp;work</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;tail&nbsp;=&nbsp;t;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;result;<br />
}</div>
<div class="sourceCode">
<pre class="sourceCode java"><br />
</pre>
</div>
<h2 id="peekfirst">peekFirst()</h2>
<p><code>peekFirst()</code>的作用是返回但不删除<em>Deque</em>首端元素，也即是<code>head</code>位置处的元素，直接返回<code>elements[head]</code>即可。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span>&nbsp;E&nbsp;peekFirst()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;elements[head];&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;elements[head]&nbsp;is&nbsp;null&nbsp;if&nbsp;deque&nbsp;empty</span><span style="color: #008000; "><br />
</span>}</div>
<div class="sourceCode">
<pre class="sourceCode java"><br />
</pre>
</div>
<h2 id="peeklast">peekLast()</h2>
<p><code>peekLast()</code>的作用是返回但不删除<em>Deque</em>尾端元素，也即是<code>tail</code>位置前面的那个元素。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span>&nbsp;E&nbsp;peekLast()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;elements[(tail&nbsp;-&nbsp;1)&nbsp;&amp;&nbsp;(elements.length&nbsp;-&nbsp;1)];<br />
}</div>
</div>
<div id="MySignature"></div><img src ="http://www.blogjava.net/CarpenterLee/aggbug/430396.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/CarpenterLee/" target="_blank">CarpenterLee</a> 2016-05-07 18:30 <a href="http://www.blogjava.net/CarpenterLee/archive/2016/05/07/430396.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java LinkedList源码剖析</title><link>http://www.blogjava.net/CarpenterLee/archive/2016/05/04/430333.html</link><dc:creator>CarpenterLee</dc:creator><author>CarpenterLee</author><pubDate>Wed, 04 May 2016 00:35:00 GMT</pubDate><guid>http://www.blogjava.net/CarpenterLee/archive/2016/05/04/430333.html</guid><wfw:comment>http://www.blogjava.net/CarpenterLee/comments/430333.html</wfw:comment><comments>http://www.blogjava.net/CarpenterLee/archive/2016/05/04/430333.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/CarpenterLee/comments/commentRss/430333.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/CarpenterLee/services/trackbacks/430333.html</trackback:ping><description><![CDATA[<h1 id="linkedlist">LinkedList</h1>
<p><a href="https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/3-LinkedList.md">本文github地址</a></p>
<h1 id="总体介绍">总体介绍</h1>
<p><em>LinkedList</em>同时实现了<em>List</em>接口和<em>Deque</em>接口，也就是说它既可以看作一个顺序容器，又可以看作一个队列（<em>Queue</em>），同时又可以看作一个栈（<em>Stack</em>）。这样看来，<em>LinkedList</em>简直就是个全能冠军。当你需要使用栈或者队列时，可以考虑使用<em>LinkedList</em>，一方面是因为Java官方已经声明不建议使用<em>Stack</em>类，更遗憾的是，Java里根本没有一个叫做<em>Queue</em>的类（它是个接口名字）。关于栈或队列，现在的首选是<em>ArrayDeque</em>，它有着比<em>LinkedList</em>（当作栈或队列使用时）有着更好的性能。</p>
<p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160504081421341-1905413637.png" alt="LinkedList_base" /></p>
<p><em>LinkedList</em>底层<strong>通过双向链表实现</strong>，本节将着重讲解插入和删除元素时双向链表的维护过程，也即是之间解跟<em>List</em>接口相关的函数，而将<em>Queue</em>和<em>Stack</em>以及<em>Deque</em>相关的知识放在下一节讲。双向链表的每个节点用内部类<em>Node</em>表示。<em>LinkedList</em>通过<code>first</code>和<code>last</code>引用分别指向链表的第一个和最后一个元素。注意这里没有所谓的哑元，当链表为空的时候<code>first</code>和<code>last</code>都指向<code>null</code>。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008000; ">//</span><span style="color: #008000; ">Node内部类</span><span style="color: #008000; "><br />
</span><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Node&lt;E&gt;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;E&nbsp;item;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Node&lt;E&gt;&nbsp;next;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Node&lt;E&gt;&nbsp;prev;<br />
&nbsp;&nbsp;&nbsp;&nbsp;Node(Node&lt;E&gt;&nbsp;prev,&nbsp;E&nbsp;element,&nbsp;Node&lt;E&gt;&nbsp;next)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.item&nbsp;=&nbsp;element;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.next&nbsp;=&nbsp;next;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.prev&nbsp;=&nbsp;prev;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</div>
<p><em>LinkedList</em>的实现方式决定了所有跟下标相关的操作都是线性时间，而在首段或者末尾删除元素只需要常数时间。为追求效率<em>LinkedList</em>没有实现同步（synchronized），如果需要多个线程并发访问，可以先采用<code>Collections.synchronizedList()</code>方法对其进行包装。</p>
<h1 id="方法剖析">方法剖析</h1>
<h2 id="add">add()</h2>
<p><em>add()</em>方法有两个版本，一个是<code>add(E e)</code>，该方法在<em>LinkedList</em>的末尾插入元素，因为有<code>last</code>指向链表末尾，在末尾插入元素的花费是常数时间。只需要简单修改几个相关引用即可；另一个是<code>add(int index, E element)</code>，该方法是在指定下表处插入元素，需要先通过线性查找找到具体位置，然后修改相关引用完成插入操作。</p>
<p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160504083959872-483694120.png" alt="LinkedList_add" /></p>
<p>结合上图，可以看出<code>add(E e)</code>的逻辑非常简单。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008000; ">//</span><span style="color: #008000; ">add(E&nbsp;e)</span><span style="color: #008000; "><br />
</span><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;add(E&nbsp;e)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Node&lt;E&gt;&nbsp;l&nbsp;=&nbsp;last;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Node&lt;E&gt;&nbsp;newNode&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Node&lt;&gt;(l,&nbsp;e,&nbsp;<span style="color: #0000FF; ">null</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;last&nbsp;=&nbsp;newNode;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(l&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;first&nbsp;=&nbsp;newNode;<span style="color: #008000; ">//</span><span style="color: #008000; ">原来链表为空，这是插入的第一个元素</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;l.next&nbsp;=&nbsp;newNode;<br />
&nbsp;&nbsp;&nbsp;&nbsp;size++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">true</span>;<br />
}</div>
<p><code><br />
add(int index, E element)</code>的逻辑稍显复杂，可以分成两部，1.先根据index找到要插入的位置；2.修改引用，完成插入操作。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008000; ">//</span><span style="color: #008000; ">add(int&nbsp;index,&nbsp;E&nbsp;element)</span><span style="color: #008000; "><br />
</span><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;add(<span style="color: #0000FF; ">int</span>&nbsp;index,&nbsp;E&nbsp;element)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;checkPositionIndex(index);<span style="color: #008000; ">//</span><span style="color: #008000; ">index&nbsp;&gt;=&nbsp;0&nbsp;&amp;&amp;&nbsp;index&nbsp;&lt;=&nbsp;size;</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(index&nbsp;==&nbsp;size)<span style="color: #008000; ">//</span><span style="color: #008000; ">插入位置是末尾，包括列表为空的情况</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add(element);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span>{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node&lt;E&gt;&nbsp;succ&nbsp;=&nbsp;node(index);<span style="color: #008000; ">//</span><span style="color: #008000; ">1.先根据index找到要插入的位置<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">2.修改引用，完成插入操作。</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Node&lt;E&gt;&nbsp;pred&nbsp;=&nbsp;succ.prev;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Node&lt;E&gt;&nbsp;newNode&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Node&lt;&gt;(pred,&nbsp;e,&nbsp;succ);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;succ.prev&nbsp;=&nbsp;newNode;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(pred&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)<span style="color: #008000; ">//</span><span style="color: #008000; ">插入位置为0</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;first&nbsp;=&nbsp;newNode;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pred.next&nbsp;=&nbsp;newNode;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</div>
<p>上面代码中的<code>node(int index)</code>函数有一点小小的trick，因为链表双向的，可以从开始往后找，也可以从结尾往前找，具体朝那个方向找取决于条件<code>index &lt; (size &gt;&gt; 1)</code>，也即是index是靠近前端还是后端。</p>
<h2 id="remove">remove()</h2>
<p><code>remove()</code>方法也有两个版本，一个是删除跟指定元素相等的第一个元素<code>remove(Object o)</code>，另一个是删除指定下标处的元素<code>remove(int index)</code>。</p>
<p><img src="http://images2015.cnblogs.com/blog/939998/201605/939998-20160504084004872-599947724.png" alt="LinkedList_remove" /></p>
<p>两个删除操作都要1.先找到要删除元素的引用，2.修改相关引用，完成删除操作。在寻找被删元素引用的时候<code>remove(Object o)</code>调用的是元素的<code>equals</code>方法，而<code>remove(int index)</code>使用的是下标计数，两种方式都是线性时间复杂度。在步骤2中，两个<code>revome()</code>方法都是通过<code>unlink(Node&lt;E&gt; x)</code>方法完成的。这里需要考虑删除元素是第一个或者最后一个时的边界情况。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008000; ">//</span><span style="color: #008000; ">unlink(Node&lt;E&gt;&nbsp;x)，删除一个Node</span><span style="color: #008000; "><br />
</span>E&nbsp;unlink(Node&lt;E&gt;&nbsp;x)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;E&nbsp;element&nbsp;=&nbsp;x.item;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Node&lt;E&gt;&nbsp;next&nbsp;=&nbsp;x.next;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Node&lt;E&gt;&nbsp;prev&nbsp;=&nbsp;x.prev;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(prev&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<span style="color: #008000; ">//</span><span style="color: #008000; ">删除的是第一个元素</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;first&nbsp;=&nbsp;next;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prev.next&nbsp;=&nbsp;next;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x.prev&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(next&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<span style="color: #008000; ">//</span><span style="color: #008000; ">删除的是最后一个元素</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;last&nbsp;=&nbsp;prev;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">else</span>&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next.prev&nbsp;=&nbsp;prev;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x.next&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;x.item&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<span style="color: #008000; ">//</span><span style="color: #008000; ">let&nbsp;GC&nbsp;work</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;size--;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;element;<br />
}</div>
<h1 id="get">get()</h1>
<p><code>get(int index)</code>得到指定下标处元素的引用，通过调用上文中提到的<code>node(int index)</code>方法实现。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span>&nbsp;E&nbsp;get(<span style="color: #0000FF; ">int</span>&nbsp;index)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;checkElementIndex(index);<span style="color: #008000; ">//</span><span style="color: #008000; ">index&nbsp;&gt;=&nbsp;0&nbsp;&amp;&amp;&nbsp;index&nbsp;&lt;&nbsp;size;</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;node(index).item;<br />
}</div>
<h1 id="set">set()</h1>
<p><code>set(int index, E element)</code>方法将指定下标处的元素修改成指定值，也是先通过<code>node(int index)</code>找到对应下表元素的引用，然后修改<code>Node</code>中<code>item</code>的值。<br />
</p>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000FF; ">public</span>&nbsp;E&nbsp;set(<span style="color: #0000FF; ">int</span>&nbsp;index,&nbsp;E&nbsp;element)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;checkElementIndex(index);<br />
&nbsp;&nbsp;&nbsp;&nbsp;Node&lt;E&gt;&nbsp;x&nbsp;=&nbsp;node(index);<br />
&nbsp;&nbsp;&nbsp;&nbsp;E&nbsp;oldVal&nbsp;=&nbsp;x.item;<br />
&nbsp;&nbsp;&nbsp;&nbsp;x.item&nbsp;=&nbsp;element;<span style="color: #008000; ">//</span><span style="color: #008000; ">替换新值</span><span style="color: #008000; "><br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;oldVal;<br />
}</div><img src ="http://www.blogjava.net/CarpenterLee/aggbug/430333.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/CarpenterLee/" target="_blank">CarpenterLee</a> 2016-05-04 08:35 <a href="http://www.blogjava.net/CarpenterLee/archive/2016/05/04/430333.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>