﻿<?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-Chan Chen Coding...-文章分类-Algorithm</title><link>http://www.blogjava.net/czihong/category/52083.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 26 Apr 2013 13:07:47 GMT</lastBuildDate><pubDate>Fri, 26 Apr 2013 13:07:47 GMT</pubDate><ttl>60</ttl><item><title>一致性hash算法 - consistent hashing</title><link>http://www.blogjava.net/czihong/articles/398076.html</link><dc:creator>Chan Chen</dc:creator><author>Chan Chen</author><pubDate>Fri, 19 Apr 2013 03:16:00 GMT</pubDate><guid>http://www.blogjava.net/czihong/articles/398076.html</guid><wfw:comment>http://www.blogjava.net/czihong/comments/398076.html</wfw:comment><comments>http://www.blogjava.net/czihong/articles/398076.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/czihong/comments/commentRss/398076.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/czihong/services/trackbacks/398076.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;">Refer to:&nbsp;<a href="http://blog.csdn.net/sparkliang/article/details/5279393">http://blog.csdn.net/sparkliang/article/details/5279393<br /></a><br />consistent hashing&nbsp;<span style="font-family: 宋体;">算法早在</span>&nbsp;1997&nbsp;<span style="font-family: 宋体;">年就在论文</span>&nbsp;<strong><a href="http://portal.acm.org/citation.cfm?id=258660" target="_blank" style="color: #336699; text-decoration: none;">Consistent hashing and random trees</a>&nbsp;</strong><span style="font-family: 宋体;">中被提出，目前在</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">系统中应用越来越广泛；</span></p><h2><a name="t1" style="color: rgb(51, 102, 153);"></a>1&nbsp;基本场景</h2><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">比如你有</span>&nbsp;N&nbsp;<span style="font-family: 宋体;">个</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">服务器（后面简称</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">），那么如何将一个对象</span>&nbsp;object&nbsp;<span style="font-family: 宋体;">映射到</span>&nbsp;N&nbsp;<span style="font-family: 宋体;">个</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">上呢，你很可能会采用类似下面的通用方法计算</span>&nbsp;object&nbsp;<span style="font-family: 宋体;">的</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">值，然后均匀的映射到到</span>&nbsp;N&nbsp;<span style="font-family: 宋体;">个</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">；</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">hash(object)%N</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">一切都运行正常，再考虑如下的两种情况；</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">1&nbsp;<span style="font-family: 宋体;">一个</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">服务器</span>&nbsp;m down&nbsp;<span style="font-family: 宋体;">掉了（在实际应用中必须要考虑这种情况），这样所有映射到</span>&nbsp;cache m&nbsp;<span style="font-family: 宋体;">的对象都会失效，怎么办，需要把</span>&nbsp;cache m&nbsp;<span style="font-family: 宋体;">从</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">中移除，这时候</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">是</span>&nbsp;N-1&nbsp;<span style="font-family: 宋体;">台，映射公式变成了</span>&nbsp;hash(object)%(N-1)&nbsp;<span style="font-family: 宋体;">；</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">2&nbsp;<span style="font-family: 宋体;">由于访问加重，需要添加</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">，这时候</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">是</span>&nbsp;N+1&nbsp;<span style="font-family: 宋体;">台，映射公式变成了</span>&nbsp;hash(object)%(N+1)&nbsp;<span style="font-family: 宋体;">；</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;">1&nbsp;<span style="font-family: 宋体;">和</span>&nbsp;2&nbsp;<span style="font-family: 宋体;">意味着什么？这意味着突然之间几乎所有的</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">都失效了。对于服务器而言，这是一场灾难，洪水般的访问都会直接冲向后台服务器；</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">再来考虑第三个问题，由于硬件能力越来越强，你可能想让后面添加的节点多做点活，显然上面的</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">算法也做不到。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;<span style="font-family: 宋体;">有什么方法可以改变这个状况呢，这就是</span>&nbsp;consistent hashing...</p><h2><a name="t2" style="color: rgb(51, 102, 153);"></a>2 hash&nbsp;算法和单调性</h2><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">　　</span>&nbsp;Hash&nbsp;<span style="font-family: 宋体;">算法的一个衡量指标是单调性（</span>&nbsp;Monotonicity&nbsp;<span style="font-family: 宋体;">），定义如下：</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">　　单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中，又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲中去，而不会被映射到旧的缓冲集合中的其他缓冲区。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">容易看到，上面的简单</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">算法</span>&nbsp;hash(object)%N&nbsp;<span style="font-family: 宋体;">难以满足单调性要求。</span></p><h2><a name="t3" style="color: rgb(51, 102, 153);"></a>3 consistent hashing&nbsp;算法的原理</h2><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;">consistent hashing&nbsp;<span style="font-family: 宋体;">是一种</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">算法，简单的说，在移除</span>&nbsp;/&nbsp;<span style="font-family: 宋体;">添加一个</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">时，它能够尽可能小的改变已存在</span>&nbsp;key&nbsp;<span style="font-family: 宋体;">映射关系，尽可能的满足单调性的要求。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">下面就来按照</span>&nbsp;5&nbsp;<span style="font-family: 宋体;">个步骤简单讲讲</span>&nbsp;consistent hashing&nbsp;<span style="font-family: 宋体;">算法的基本原理。</span></p><h3><a name="t4" style="color: rgb(51, 102, 153);"></a>3.1&nbsp;环形hash&nbsp;空间</h3><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">考虑通常的</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">算法都是将</span>&nbsp;value&nbsp;<span style="font-family: 宋体;">映射到一个</span>&nbsp;32&nbsp;<span style="font-family: 宋体;">为的</span>&nbsp;key&nbsp;<span style="font-family: 宋体;">值，也即是</span>&nbsp;0~2^32-1&nbsp;<span style="font-family: 宋体;">次方的数值空间；我们可以将这个空间想象成一个首（</span>&nbsp;0&nbsp;<span style="font-family: 宋体;">）尾（</span>&nbsp;2^32-1&nbsp;<span style="font-family: 宋体;">）相接的圆环，如下面图</span>&nbsp;1&nbsp;<span style="font-family: 宋体;">所示的那样。</span></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><img src="http://www.codeproject.com/KB/recipes/lib-conhash/circle.JPG" alt="circle space" width="91" height="104" style="border: 0pt none;" /></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">图</span>&nbsp;1&nbsp;<span style="font-family: 宋体;">环形</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">空间</span></p><h3><a name="t5" style="color: rgb(51, 102, 153);"></a>3.2&nbsp;把对象映射到hash&nbsp;空间</h3><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">接下来考虑</span>&nbsp;4&nbsp;<span style="font-family: 宋体;">个对象</span>&nbsp;object1~object4&nbsp;<span style="font-family: 宋体;">，通过</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">函数计算出的</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">值</span>&nbsp;key&nbsp;<span style="font-family: 宋体;">在环上的分布如图</span>&nbsp;2&nbsp;<span style="font-family: 宋体;">所示。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">hash(object1) = key1;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&#8230; &#8230;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">hash(object4) = key4;</p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><img src="http://www.codeproject.com/KB/recipes/lib-conhash/object.JPG" alt="object" width="234" height="253" style="border: 0pt none;" /></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">图</span>&nbsp;2 4&nbsp;<span style="font-family: 宋体;">个对象的</span>&nbsp;key&nbsp;<span style="font-family: 宋体;">值分布</span></p><h3><a name="t6" style="color: rgb(51, 102, 153);"></a>3.3&nbsp;把cache&nbsp;映射到hash&nbsp;空间</h3><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;">Consistent hashing&nbsp;<span style="font-family: 宋体;">的基本思想就是将对象和</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">都映射到同一个</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">数值空间中，并且使用相同的</span>hash&nbsp;<span style="font-family: 宋体;">算法。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">假设当前有</span>&nbsp;A,B&nbsp;<span style="font-family: 宋体;">和</span>&nbsp;C&nbsp;<span style="font-family: 宋体;">共</span>&nbsp;3&nbsp;<span style="font-family: 宋体;">台</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">，那么其映射结果将如图</span>&nbsp;3&nbsp;<span style="font-family: 宋体;">所示，他们在</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">空间中，以对应的</span>&nbsp;hash<span style="font-family: 宋体;">值排列。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">hash(cache A) = key A;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&#8230; &#8230;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">hash(cache C) = key C;</p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><img src="http://www.codeproject.com/KB/recipes/lib-conhash/cache.JPG" alt="cache" width="283" height="253" style="border: 0pt none;" /></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">图</span>&nbsp;3 cache&nbsp;<span style="font-family: 宋体;">和对象的</span>&nbsp;key&nbsp;<span style="font-family: 宋体;">值分布</span></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">说到这里，顺便提一下</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">的</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">计算，一般的方法可以使用</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">机器的</span>&nbsp;IP&nbsp;<span style="font-family: 宋体;">地址或者机器名作为</span>hash&nbsp;<span style="font-family: 宋体;">输入。</span></p><h3><a name="t7" style="color: rgb(51, 102, 153);"></a>3.4&nbsp;把对象映射到cache</h3><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">现在</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">和对象都已经通过同一个</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">算法映射到</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">数值空间中了，接下来要考虑的就是如何将对象映射到</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">上面了。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">在这个环形空间中，如果沿着顺时针方向从对象的</span>&nbsp;key&nbsp;<span style="font-family: 宋体;">值出发，直到遇见一个</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">，那么就将该对象存储在这个</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">上，因为对象和</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">的</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">值是固定的，因此这个</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">必然是唯一和确定的。这样不就找到了对象和</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">的映射方法了吗？！</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">依然继续上面的例子（参见图</span>&nbsp;3&nbsp;<span style="font-family: 宋体;">），那么根据上面的方法，对象</span>&nbsp;object1&nbsp;<span style="font-family: 宋体;">将被存储到</span>&nbsp;cache A&nbsp;<span style="font-family: 宋体;">上；</span>&nbsp;object2<span style="font-family: 宋体;">和</span>&nbsp;object3&nbsp;<span style="font-family: 宋体;">对应到</span>&nbsp;cache C&nbsp;<span style="font-family: 宋体;">；</span>&nbsp;object4&nbsp;<span style="font-family: 宋体;">对应到</span>&nbsp;cache B&nbsp;<span style="font-family: 宋体;">；</span></p><h3><a name="t8" style="color: rgb(51, 102, 153);"></a>3.5&nbsp;考察cache&nbsp;的变动</h3><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">前面讲过，通过</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">然后求余的方法带来的最大问题就在于不能满足单调性，当</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">有所变动时，</span>cache&nbsp;<span style="font-family: 宋体;">会失效，进而对后台服务器造成巨大的冲击，现在就来分析分析</span>&nbsp;consistent hashing&nbsp;<span style="font-family: 宋体;">算法。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><strong>3.5.1&nbsp;</strong><strong><span style="font-family: 宋体;">移除</span>&nbsp;cache</strong></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">考虑假设</span>&nbsp;cache B&nbsp;<span style="font-family: 宋体;">挂掉了，根据上面讲到的映射方法，这时受影响的将仅是那些沿</span>&nbsp;cache B&nbsp;<span style="font-family: 宋体;">逆时针遍历直到下一个</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">（</span>&nbsp;cache C&nbsp;<span style="font-family: 宋体;">）之间的对象，也即是本来映射到</span>&nbsp;cache B&nbsp;<span style="font-family: 宋体;">上的那些对象。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">因此这里仅需要变动对象</span>&nbsp;object4&nbsp;<span style="font-family: 宋体;">，将其重新映射到</span>&nbsp;cache C&nbsp;<span style="font-family: 宋体;">上即可；参见图</span>&nbsp;4&nbsp;<span style="font-family: 宋体;">。</span></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><img src="http://www.codeproject.com/KB/recipes/lib-conhash/remove.JPG" alt="remove" width="283" height="253" style="border: 0pt none;" /></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">图</span>&nbsp;4 Cache B&nbsp;<span style="font-family: 宋体;">被移除后的</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">映射</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><strong>3.5.2&nbsp;</strong><strong><span style="font-family: 宋体;">添加</span>&nbsp;cache</strong></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">再考虑添加一台新的</span>&nbsp;cache D&nbsp;<span style="font-family: 宋体;">的情况，假设在这个环形</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">空间中，</span>&nbsp;cache D&nbsp;<span style="font-family: 宋体;">被映射在对象</span>&nbsp;object2&nbsp;<span style="font-family: 宋体;">和</span>object3&nbsp;<span style="font-family: 宋体;">之间。这时受影响的将仅是那些沿</span>&nbsp;cache D&nbsp;<span style="font-family: 宋体;">逆时针遍历直到下一个</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">（</span>&nbsp;cache B&nbsp;<span style="font-family: 宋体;">）之间的对象（它们是也本来映射到</span>&nbsp;cache C&nbsp;<span style="font-family: 宋体;">上对象的一部分），将这些对象重新映射到</span>&nbsp;cache D&nbsp;<span style="font-family: 宋体;">上即可。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">因此这里仅需要变动对象</span>&nbsp;object2&nbsp;<span style="font-family: 宋体;">，将其重新映射到</span>&nbsp;cache D&nbsp;<span style="font-family: 宋体;">上；参见图</span>&nbsp;5&nbsp;<span style="font-family: 宋体;">。</span></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><img src="http://www.codeproject.com/KB/recipes/lib-conhash/add.JPG" alt="add" width="283" height="253" style="border: 0pt none;" /></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">图</span>&nbsp;5&nbsp;<span style="font-family: 宋体;">添加</span>&nbsp;cache D&nbsp;<span style="font-family: 宋体;">后的映射关系</span></p><h2><a name="t9" style="color: rgb(51, 102, 153);"></a>4&nbsp;虚拟节点</h2><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">考量</span>&nbsp;Hash&nbsp;<span style="font-family: 宋体;">算法的另一个指标是平衡性</span>&nbsp;(Balance)&nbsp;<span style="font-family: 宋体;">，定义如下：</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">平衡性</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">　　平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去，这样可以使得所有的缓冲空间都得到利用。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">hash&nbsp;<span style="font-family: 宋体;">算法并不是保证绝对的平衡，如果</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">较少的话，对象并不能被均匀的映射到</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">上，比如在上面的例子中，仅部署</span>&nbsp;cache A&nbsp;<span style="font-family: 宋体;">和</span>&nbsp;cache C&nbsp;<span style="font-family: 宋体;">的情况下，在</span>&nbsp;4&nbsp;<span style="font-family: 宋体;">个对象中，</span>&nbsp;cache A&nbsp;<span style="font-family: 宋体;">仅存储了</span>&nbsp;object1&nbsp;<span style="font-family: 宋体;">，而</span>&nbsp;cache C&nbsp;<span style="font-family: 宋体;">则存储了</span>&nbsp;object2&nbsp;<span style="font-family: 宋体;">、</span>&nbsp;object3&nbsp;<span style="font-family: 宋体;">和</span>&nbsp;object4&nbsp;<span style="font-family: 宋体;">；分布是很不均衡的。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">为了解决这种情况，</span>&nbsp;consistent hashing&nbsp;<span style="font-family: 宋体;">引入了&#8220;虚拟节点&#8221;的概念，它可以如下定义：</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">&#8220;虚拟节点&#8221;（</span>&nbsp;virtual node&nbsp;<span style="font-family: 宋体;">）是实际节点在</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">空间的复制品（</span>&nbsp;replica&nbsp;<span style="font-family: 宋体;">），一实际个节点对应了若干个&#8220;虚拟节点&#8221;，这个对应个数也成为&#8220;复制个数&#8221;，&#8220;虚拟节点&#8221;在</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">空间中以</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">值排列。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">仍以仅部署</span>&nbsp;cache A&nbsp;<span style="font-family: 宋体;">和</span>&nbsp;cache C&nbsp;<span style="font-family: 宋体;">的情况为例，在图</span>&nbsp;4&nbsp;<span style="font-family: 宋体;">中我们已经看到，</span>&nbsp;cache&nbsp;<span style="font-family: 宋体;">分布并不均匀。现在我们引入虚拟节点，并设置&#8220;复制个数&#8221;为</span>&nbsp;2&nbsp;<span style="font-family: 宋体;">，这就意味着一共会存在</span>&nbsp;4&nbsp;<span style="font-family: 宋体;">个&#8220;虚拟节点&#8221;，</span>&nbsp;cache A1, cache A2&nbsp;<span style="font-family: 宋体;">代表了</span>&nbsp;cache A&nbsp;<span style="font-family: 宋体;">；</span>&nbsp;cache C1, cache C2&nbsp;<span style="font-family: 宋体;">代表了</span>&nbsp;cache C&nbsp;<span style="font-family: 宋体;">；假设一种比较理想的情况，参见图</span>&nbsp;6&nbsp;<span style="font-family: 宋体;">。</span></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><img src="http://www.codeproject.com/KB/recipes/lib-conhash/virtual.JPG" alt="virtual nodes" width="283" height="253" style="border: 0pt none;" /></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">图</span>&nbsp;6&nbsp;<span style="font-family: 宋体;">引入&#8220;虚拟节点&#8221;后的映射关系</span></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">此时，对象到&#8220;虚拟节点&#8221;的映射关系为：</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">objec1-&gt;cache A2&nbsp;<span style="font-family: 宋体;">；</span>&nbsp;objec2-&gt;cache A1&nbsp;<span style="font-family: 宋体;">；</span>&nbsp;objec3-&gt;cache C1&nbsp;<span style="font-family: 宋体;">；</span>&nbsp;objec4-&gt;cache C2&nbsp;<span style="font-family: 宋体;">；</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">因此对象</span>&nbsp;object1&nbsp;<span style="font-family: 宋体;">和</span>&nbsp;object2&nbsp;<span style="font-family: 宋体;">都被映射到了</span>&nbsp;cache A&nbsp;<span style="font-family: 宋体;">上，而</span>&nbsp;object3&nbsp;<span style="font-family: 宋体;">和</span>&nbsp;object4&nbsp;<span style="font-family: 宋体;">映射到了</span>&nbsp;cache C&nbsp;<span style="font-family: 宋体;">上；平衡性有了很大提高。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">引入&#8220;虚拟节点&#8221;后，映射关系就从</span>&nbsp;{&nbsp;<span style="font-family: 宋体;">对象</span>&nbsp;-&gt;&nbsp;<span style="font-family: 宋体;">节点</span>&nbsp;}&nbsp;<span style="font-family: 宋体;">转换到了</span>&nbsp;{&nbsp;<span style="font-family: 宋体;">对象</span>&nbsp;-&gt;&nbsp;<span style="font-family: 宋体;">虚拟节点</span>&nbsp;}&nbsp;<span style="font-family: 宋体;">。查询物体所在</span>&nbsp;cache<span style="font-family: 宋体;">时的映射关系如图</span>&nbsp;7&nbsp;<span style="font-family: 宋体;">所示。</span></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><img src="http://www.codeproject.com/KB/recipes/lib-conhash/map.JPG" alt="map" width="529" height="232" style="border: 0pt none;" /></p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">图</span>&nbsp;7&nbsp;<span style="font-family: 宋体;">查询对象所在</span>&nbsp;cache</p><p align="center" style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;">&#8220;虚拟节点&#8221;的</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">计算可以采用对应节点的</span>&nbsp;IP&nbsp;<span style="font-family: 宋体;">地址加数字后缀的方式。例如假设</span>&nbsp;cache A&nbsp;<span style="font-family: 宋体;">的</span>&nbsp;IP&nbsp;<span style="font-family: 宋体;">地址为</span>202.168.14.241&nbsp;<span style="font-family: 宋体;">。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">引入&#8220;虚拟节点&#8221;前，计算</span>&nbsp;cache A&nbsp;<span style="font-family: 宋体;">的</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">值：</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">Hash(&#8220;202.168.14.241&#8221;);</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">引入&#8220;虚拟节点&#8221;后，计算&#8220;虚拟节&#8221;点</span>&nbsp;cache A1&nbsp;<span style="font-family: 宋体;">和</span>&nbsp;cache A2&nbsp;<span style="font-family: 宋体;">的</span>&nbsp;hash&nbsp;<span style="font-family: 宋体;">值：</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">Hash(&#8220;202.168.14.241#1&#8221;);&nbsp;&nbsp;// cache A1</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">Hash(&#8220;202.168.14.241#2&#8221;);&nbsp;&nbsp;// cache A2</p><h2><a name="t10" style="color: rgb(51, 102, 153);"></a>5&nbsp;小结</h2><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;">Consistent hashing&nbsp;<span style="font-family: 宋体;">的基本原理就是这些，具体的分布性等理论分析应该是很复杂的，不过一般也用不到。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><a href="http://weblogs.java.net/blog/2007/11/27/consistent-hashing" style="color: #336699; text-decoration: none;">http://weblogs.java.net/blog/2007/11/27/consistent-hashing</a>&nbsp;<span style="font-family: 宋体;">上面有一个</span>&nbsp;java&nbsp;<span style="font-family: 宋体;">版本的例子，可以参考。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><a href="http://blog.csdn.net/mayongzhan/archive/2009/06/25/4298834.aspx" style="color: #336699; text-decoration: none;">http://blog.csdn.net/mayongzhan/archive/2009/06/25/4298834.aspx</a>&nbsp;<span style="font-family: 宋体;">转载了一个</span>&nbsp;PHP&nbsp;<span style="font-family: 宋体;">版的实现代码。</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;"><a href="http://www.codeproject.com/KB/recipes/lib-conhash.aspx" style="color: #336699; text-decoration: none;">http://www.codeproject.com/KB/recipes/lib-conhash.aspx</a>&nbsp;C语言版本<br /></span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff; text-indent: 21pt;"><span style="font-family: 宋体;"><br /></span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="font-family: 宋体;">一些参考资料地址：</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><a href="http://portal.acm.org/citation.cfm?id=258660" target="_blank" style="color: #336699; text-decoration: none;">http://portal.acm.org/citation.cfm?id=258660</a></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><a href="http://en.wikipedia.org/wiki/Consistent_hashing" target="_blank" style="color: #336699; text-decoration: none;">http://en.wikipedia.org/wiki/Consistent_hashing</a></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><a href="http://www.spiteful.com/2008/03/17/programmers-toolbox-part-3-consistent-hashing/" target="_blank" style="color: #336699; text-decoration: none;">http://www.spiteful.com/2008/03/17/programmers-toolbox-part-3-consistent-hashing/</a></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;<a href="http://weblogs.java.net/blog/2007/11/27/consistent-hashing" style="color: #336699; text-decoration: none;">http://weblogs.java.net/blog/2007/11/27/consistent-hashing</a></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><a href="http://tech.idv2.com/2008/07/24/memcached-004/" style="color: #336699; text-decoration: none;">http://tech.idv2.com/2008/07/24/memcached-004/</a></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><a href="http://blog.csdn.net/mayongzhan/archive/2009/06/25/4298834.aspx" style="color: #336699; text-decoration: none;">http://blog.csdn.net/mayongzhan/archive/2009/06/25/4298834.aspx</a></p><img src ="http://www.blogjava.net/czihong/aggbug/398076.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/czihong/" target="_blank">Chan Chen</a> 2013-04-19 11:16 <a href="http://www.blogjava.net/czihong/articles/398076.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hacker News算法</title><link>http://www.blogjava.net/czihong/articles/396897.html</link><dc:creator>Chan Chen</dc:creator><author>Chan Chen</author><pubDate>Sat, 23 Mar 2013 05:35:00 GMT</pubDate><guid>http://www.blogjava.net/czihong/articles/396897.html</guid><wfw:comment>http://www.blogjava.net/czihong/comments/396897.html</wfw:comment><comments>http://www.blogjava.net/czihong/articles/396897.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/czihong/comments/commentRss/396897.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/czihong/services/trackbacks/396897.html</trackback:ping><description><![CDATA[<p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;"><a href="http://news.ycombinator.com/" target="_blank" style="margin: 0px; padding: 0px; list-style-type: none; border: none; color: #112233;">Hacker News</a>是一个网络社区，可以张贴链接，或者讨论某个主题。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;"><img src="http://image.beekka.com/blog/201202/bg2012022403.png" style="margin: 0px; padding: 0px; list-style-type: none; border: 1px solid gray;"  alt="" /></p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">每个帖子前面有一个向上的三角形，如果你觉得这个内容很好，就点击一下，投上一票。根据得票数，系统自动统计出热门文章排行榜。但是，并非得票最多的文章排在第一位，还要考虑时间因素，新文章应该比旧文章更容易得到好的排名。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">Hacker News使用Paul Graham开发的Arc语言编写，源码可以从<a href="http://arclanguage.org/" target="_blank" style="margin: 0px; padding: 0px; list-style-type: none; border: none; color: #112233;">arclanguage.org</a>下载。它的排名算法是<a href="http://pastebin.com/ZF57qQPi" target="_blank" style="margin: 0px; padding: 0px; list-style-type: none; border: none; color: #112233;">这样</a>实现的：</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;"><a href="http://pastebin.com/ZF57qQPi" target="_blank" style="margin: 0px; padding: 0px; list-style-type: none; border: none; color: #112233;"><img src="http://image.beekka.com/blog/201202/bg2012022404.png" style="margin: 0px; padding: 0px; list-style-type: none; text-decoration: none; border: 1px solid gray; color: #111111;"  alt="" /></a></p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">将上面的代码还原为数学公式：</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;"><img src="http://chart.googleapis.com/chart?cht=tx&amp;chl=Score%3D%5Cfrac%7BP-1%7D%7B(T%2B2)%5E%7BG%7D%7D&amp;chs=60" style="margin: 0px; padding: 0px; list-style-type: none; border: none;"  alt="" /></p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">其中，</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">　　P表示帖子的得票数，减去1是为了忽略发帖人的投票。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">　　T表示距离发帖的时间（单位为小时），加上2是为了防止最新的帖子导致分母过小（之所以选择2，可能是因为从原始文章出现在其他网站，到转贴至Hacker News，平均需要两个小时）。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">　　G表示"重力因子"（gravityth power），即将帖子排名往下拉的力量，默认值为1.8，后文会详细讨论这个值。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">从这个公式来看，决定帖子排名有三个因素：</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;"><strong>第一个因素是得票数P。</strong></p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">在其他条件不变的情况下，得票越多，排名越高。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;"><a href="http://www.wolframalpha.com/input/?i=plot(+(30+-+1)+%2F+(t+%2B+2)%5E1.8%2C++(60+-+1)+%2F+(t+%2B+2)%5E1.8%2C+(200+-+1)+%2F+(t+%2B+2)%5E1.8+)+where+t%3D0..24" target="_blank" style="margin: 0px; padding: 0px; list-style-type: none; border: none; color: #112233;"><img src="http://image.beekka.com/blog/201202/bg2012022405.png" style="margin: 0px; padding: 0px; list-style-type: none; text-decoration: none; border: 1px solid gray; color: #111111;"  alt="" /></a></p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">从<a href="http://www.wolframalpha.com/input/?i=plot(+(30+-+1)+%2F+(t+%2B+2)%5E1.8%2C++(60+-+1)+%2F+(t+%2B+2)%5E1.8%2C+(200+-+1)+%2F+(t+%2B+2)%5E1.8+)+where+t%3D0..24" target="_blank" style="margin: 0px; padding: 0px; list-style-type: none; border: none; color: #112233;">上图</a>可以看到，有三个同时发表的帖子，得票分别为200票、60票和30票（减1后为199、59和29），分别以黄色、紫色和蓝色表示。在任一个时间点上，都是黄色曲线在最上方，蓝色曲线在最下方。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">如果你不想让"高票帖子"与"低票帖子"的差距过大，可以在得票数上加一个小于1的指数，比如(P-1)^0.8。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;"><strong>第二个因素是距离发帖的时间T。</strong></p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">在其他条件不变的情况下，越是新发表的帖子，排名越高。或者说，一个帖子的排名，会随着时间不断下降。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">从前一张图可以看到，经过24小时之后，所有帖子的得分基本上都小于1，这意味着它们都将跌到排行榜的末尾，保证了排名前列的都将是较新的内容。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;"><strong>第三个因素是重力因子G。</strong></p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">它的数值大小决定了排名随时间下降的速度。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;"><a href="http://www.wolframalpha.com/input/?i=plot%28+%28p+-+1%29+%2F+%28t+%2B+2%29%5E2.0%2C++%28p+-+1%29+%2F+%28t+%2B+2%29%5E1.8%2C+%28p+-+1%29+%2F+%28t+%2B+2%29%5E1.5+%29+where+t%3D0..24%2C+p%3D10" target="_blank" style="margin: 0px; padding: 0px; list-style-type: none; border: none; color: #112233;"><img src="http://image.beekka.com/blog/201202/bg2012022406.png" style="margin: 0px; padding: 0px; list-style-type: none; text-decoration: none; border: 1px solid gray; color: #111111;"  alt="" /></a></p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">从<a href="http://www.wolframalpha.com/input/?i=plot%28+%28p+-+1%29+%2F+%28t+%2B+2%29%5E2.0%2C++%28p+-+1%29+%2F+%28t+%2B+2%29%5E1.8%2C+%28p+-+1%29+%2F+%28t+%2B+2%29%5E1.5+%29+where+t%3D0..24%2C+p%3D10" target="_blank" style="margin: 0px; padding: 0px; list-style-type: none; border: none; color: #112233;">上图</a>可以看到，三根曲线的其他参数都一样，G的值分别为1.5、1.8和2.0。G值越大，曲线越陡峭，排名下降得越快，意味着排行榜的更新速度越快。</p><p style="margin: 1em 0px 0px 0.8em; padding: 0px; list-style-type: none; border: none; color: #111111; font-size: 1.6em; line-height: 28px; font-family: Georgia, serif; word-spacing: 2px; background-color: #f5f5d5;">知道了算法的构成，就可以调整参数的值，以适用你自己的应用程序。</p><img src ="http://www.blogjava.net/czihong/aggbug/396897.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/czihong/" target="_blank">Chan Chen</a> 2013-03-23 13:35 <a href="http://www.blogjava.net/czihong/articles/396897.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Dynamic Programming: From novice to advanced</title><link>http://www.blogjava.net/czihong/articles/386947.html</link><dc:creator>Chan Chen</dc:creator><author>Chan Chen</author><pubDate>Tue, 04 Sep 2012 04:07:00 GMT</pubDate><guid>http://www.blogjava.net/czihong/articles/386947.html</guid><wfw:comment>http://www.blogjava.net/czihong/comments/386947.html</wfw:comment><comments>http://www.blogjava.net/czihong/articles/386947.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/czihong/comments/commentRss/386947.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/czihong/services/trackbacks/386947.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Refer to:&nbsp;http://www.topcoder.com/tc?d1=tutorials&amp;d2=dynProg&amp;module=Static&nbsp;Introduction (Beginner)What is a dynamic programming, how can it be described?&nbsp;A&nbsp;DP&nbsp;is an al...&nbsp;&nbsp;<a href='http://www.blogjava.net/czihong/articles/386947.html'>阅读全文</a><img src ="http://www.blogjava.net/czihong/aggbug/386947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/czihong/" target="_blank">Chan Chen</a> 2012-09-04 12:07 <a href="http://www.blogjava.net/czihong/articles/386947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>三色旗</title><link>http://www.blogjava.net/czihong/articles/386869.html</link><dc:creator>Chan Chen</dc:creator><author>Chan Chen</author><pubDate>Mon, 03 Sep 2012 06:47:00 GMT</pubDate><guid>http://www.blogjava.net/czihong/articles/386869.html</guid><wfw:comment>http://www.blogjava.net/czihong/comments/386869.html</wfw:comment><comments>http://www.blogjava.net/czihong/articles/386869.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/czihong/comments/commentRss/386869.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/czihong/services/trackbacks/386869.html</trackback:ping><description><![CDATA[<table border="0" cellpadding="0" cellspacing="0" style="font-family: serif; background-color: #ffffff; text-align: left; width: 946px; height: 32px; "><tbody><tr><td style="width: 676px; vertical-align: top; "><h2>&nbsp;說明</h2><small>三色旗的問題最早由E.W.Dijkstra所提出，他所使用的用語為Dutch Nation Flag(Dijkstra為荷蘭人)，而多數的作者則使用Three-Color Flag來稱之。<br /><br />假設有一條繩子，上面有紅、白、藍三種顏色的旗子，起初繩子上的旗子顏色並沒有順序，您希望將之分類，並排列為藍、白、紅的順序，要如何移動次數才會最少，注意您只能在繩子上進行這個動作，而且一次只能調換兩個旗子。</small>&nbsp;<br /><h2>解法</h2><small>在一條繩子上移動，在程式中也就意味只能使用一個陣列，而不使用其它的陣列來作輔助，問題的解法很簡單，您可以自己想像一下在移動旗子，從繩子開頭進行，遇到藍色往前移，遇到白色留在中間，遇到紅色往後移，如下所示：&nbsp;</small><br /><div style="text-align: center; "><img alt="三色旗" title="三色旗" src="http://caterpillar.onlyfun.net/Gossip/AlgorithmGossip/images/threeColorsFlags-1.jpg" style="width: 504px; height: 208px; " /></div><small>只是要讓移動次數最少的話，就要有些技巧：<br /></small><ol style="margin-top: 3px; margin-bottom: 3px; "><li><small>如果圖中W所在的位置為白色，則W+1，表示未處理的部份移至至白色群組。</small></li><li><small>如果W部份為藍色，則B與W的元素對調，而B與W必須各+1，表示兩個群組都多了一個元素。</small></li><li><small>如果W所在的位置是紅色，則將W與R交換，但R要減1，表示未處理的部份減1。</small></li></ol><small><br />注意B、W、R並不是三色旗的個數，它們只是一個移動的指標；什麼時候移動結束呢？一開始時未處理的R指標會是等於旗子的總數，當R的索引數減至少於W的索引數時，表示接下來的旗子就都是紅色了，此時就可以結束移動，如下所示：&nbsp;</small><br /><div style="text-align: center; "><img alt="三色旗" title="三色旗" src="http://caterpillar.onlyfun.net/Gossip/AlgorithmGossip/images/threeColorsFlags-2.jpg" style="width: 502px; height: 236px; " /></div><br /><small>如果可以使用雙向鏈結的話，則B可以再省去，在W遞增時，若遇到藍色，則將藍色移至鏈結前端且W+1，若遇到白色則W+1，若遇到紅色，則將紅色移至鏈結尾端且R-1。<br /><br /><div style="background-color: #eeeeee; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; border-image: initial; 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; ">import</span>&nbsp;java.io.BufferedReader;<br /><span style="color: #0000FF; ">import</span>&nbsp;java.io.IOException;<br /><span style="color: #0000FF; ">import</span>&nbsp;java.io.InputStreamReader;<br /><br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;ThreeColorFlags&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;swap(<span style="color: #0000FF; ">char</span>[]&nbsp;flags,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;x,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;y)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;temp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp&nbsp;=&nbsp;flags[x];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags[x]&nbsp;=&nbsp;flags[y];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags[y]&nbsp;=&nbsp;temp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;move(<span style="color: #0000FF; ">char</span>[]&nbsp;flags)&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;bFlag&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;wFlag&nbsp;=&nbsp;0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;rFlag&nbsp;=&nbsp;flags.length&nbsp;-&nbsp;1;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(wFlag&nbsp;&lt;=&nbsp;rFlag)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(flags[wFlag]&nbsp;==&nbsp;'W')&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wFlag++;<br />&nbsp;&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;(flags[wFlag]&nbsp;==&nbsp;'B')&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;swap(flags,&nbsp;wFlag,&nbsp;bFlag);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wFlag++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bFlag++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>(wFlag&nbsp;&lt;&nbsp;rFlag&nbsp;&amp;&amp;&nbsp;flags[rFlag]&nbsp;==&nbsp;'R'){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rFlag--;<br />&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;swap(flags,&nbsp;wFlag,&nbsp;rFlag);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rFlag--;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;String(flags);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;IOException{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BufferedReader&nbsp;buf;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;BufferedReader(<span style="color: #0000FF; ">new</span>&nbsp;InputStreamReader(System.in));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Type&nbsp;the&nbsp;sequence&nbsp;of&nbsp;three&nbsp;colors(BBWRWEBBWWRRRRWB):&nbsp;");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;flags&nbsp;=&nbsp;buf.readLine();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreeColorFlags&nbsp;threeColorFlags&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;ThreeColorFlags();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags&nbsp;=&nbsp;threeColorFlags.move(flags.toUpperCase().toCharArray());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("After&nbsp;move:&nbsp;"&nbsp;+&nbsp;flags);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div></small></td></tr></tbody></table><img src ="http://www.blogjava.net/czihong/aggbug/386869.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/czihong/" target="_blank">Chan Chen</a> 2012-09-03 14:47 <a href="http://www.blogjava.net/czihong/articles/386869.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hanoi Tower 汉诺塔的简单分析 Java</title><link>http://www.blogjava.net/czihong/articles/386673.html</link><dc:creator>Chan Chen</dc:creator><author>Chan Chen</author><pubDate>Fri, 31 Aug 2012 03:31:00 GMT</pubDate><guid>http://www.blogjava.net/czihong/articles/386673.html</guid><wfw:comment>http://www.blogjava.net/czihong/comments/386673.html</wfw:comment><comments>http://www.blogjava.net/czihong/articles/386673.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/czihong/comments/commentRss/386673.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/czihong/services/trackbacks/386673.html</trackback:ping><description><![CDATA[<p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　当然、这是一个经典的递归问题~<br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " />&nbsp;&nbsp; 　想必来看这篇博文的同学对汉诺塔应该不会陌生了吧，</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　写这篇博还是有初衷的：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　之前学数据结构的时候自己看书、也上网上查了很多资料，资料都比较散、而且描述的不是很清楚，对于当时刚刚</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">接触算法的我，要完全理解还是有一定难度。今天刚好有时间就整理了下思路、重写分析了一下之前的疑惑的地方、</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">没有透彻的地方便都豁然开朗了。所以迫不及待把我的想法记录下来，和大家分享。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　如果你也是和之前的我一样对hanoi tower没能完全消化，或者刚刚接触汉诺塔，那希望我的这种理解方式能给你些</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">许帮助，如果你觉得已经完全掌握的比较牢靠了，那也可以看看，有好的idea可以一起分享；毕竟交流讨论也是一种很好的</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">学习方式。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　好了，废话不多说，切入正题。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">关于汉诺塔起源啊、传说啊神马的就不啰嗦了，我们直接切入正题：<br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " />问题描述：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　有一个梵塔，塔内有三个座A、B、C，A座上有诺干个盘子，盘子大小不等，大的在下，小的在上（如图）。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">把这些个盘子从A座移到C座，中间可以借用B座但每次只能允许移动一个盘子，并且在移动过程中，3个座上的盘</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">子始终保持大盘在下，小盘在上。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">描述简化：把A柱上的n个盘子移动到C柱，其中可以借用B柱。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; "><img src="http://pic002.cnblogs.com/images/2011/348708/2011111320150185.gif" alt="" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; border-style: initial; border-color: initial; " /></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　我们直接假设有n个盘子：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　先把盘子从小到大标记为1、2、3......n</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　先看原问题三个柱子的状态：<br style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; " /><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #ff0000; ">状态0　　A：按顺序堆放的n个盘子。B:空的。C：空的。</span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　目标是要把A上的n个盘子移动到C。因为必须大的在下小的在上，所以最终结果C盘上最下面的应该是标号为n的盘子，试想：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">要取得A上的第n个盘子，就要把它上面的n-1个盘子拿开吧？拿开放在哪里呢？共有三个柱子：A显然不是、如果放在C上</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">了，那么最大的盘子就没地方放，问题还是没得到解决。所以选择B柱。当然，B上面也是按照大在下小在上的原则堆放的</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; "><strong style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">（记住：先不要管具体如何移动，可以看成用一个函数完成移动，现在不用去考虑函数如何实现。这点很重要）。</strong></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　很明显：上一步完成后三个塔的状态：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #ff0000; ">状态1：&nbsp;　　A：只有最大的一个盘子。B：有按规则堆放的n-1个盘子。C空的。</span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　上面的很好理解吧，好，其实到这里就已经完成一半了。（如果前面的没懂，请重看一遍。point：不要管如何移动！）</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">我们继续：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　这时候，可以直接把A上的最大盘移动到C盘，移动后的状态：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #808080; ">中间状态：　　A：空的。B：n-1个盘子。C：有一个最大盘（第n个盘子）</span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　要注意的一点是：这时候的C柱其实可以看做是空的。因为剩下的所有盘子都比它小，它们中的任何一个都可以放在上面，也就是　　　　　　&nbsp;&nbsp;&nbsp; 　　　　　　　　&nbsp; C柱上。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　所以现在三个柱子的状态：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #808080; ">中间状态：　　A：空的。B：n-1个盘子。C：空的</span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　想一想，现在的问题和原问题有些相似之处了吧？。。如何更相似呢？。显然，只要吧B上的n-1个盘子移动到A，待解决的问题和原问题就相比就只是规模变小了</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　现在考虑如何把B上的n-1个盘子移动到A上，其实移动方法和上文中的把n-1个盘从A移动到B是一样的，只是柱子的名称换了下而已。。（如果写成函数，只是参数调用顺序改变而已）。　</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">　　假设你已经完成上一步了（同样的，不要考虑如何去移动，只要想着用一个函数实现就好），请看现在的状态：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #ff0000; ">状态2：　A：有按顺序堆放的n-1个盘子。B：空的。C：按顺序堆放的第n盘子(可看为空柱)</span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">就在刚才，我们完美的完成了一次递归。如果没看懂请从新看一遍，可以用笔画出三个状态、静下心来慢慢推理。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; "><em style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">我一再强调的：当要把最大盘子上面的所有盘子移动到另一个空柱上时，不要关心具体如何移动，只用把它看做一个函数可以完成即可，不用关心函数的具体实现。如果你的思路纠结在这里，就很难继续深入了。</em></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">到这里，其实 基本思路已经理清了。状态2和状态0，除了规模变小 ，其它方面没有任何区别了。然后只要用相同的思维方式，就能往下深入。。。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">好了，看看如何用算法实现吧：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">定义函数Hanoi（a,b,c,n）表示把a上的n个盘子移动到c上，其中可以用到b。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">定义函数move(m,n)表示把m上的盘子移动到n上</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">我们需要解决的问题正是　　Hanoi (a,b,c,n)&nbsp;&nbsp;&nbsp;　　//上文中的状态0</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">1、把A上的n-1个移动到B：&nbsp; 　　Hanoi (a,c,b,n-1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;操作结束为状态1</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">2、把A上的大盘子移动到C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; move(a,c)　　　　</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">3、把B上的n-1移动到A　　　　　Hanoi (b,c,a,n-1);　　//操作结束位状态2(和状态1相比只是规模变小)</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; background-color: #c0c0c0; ">如果现在还不能理解、请回过头再看一遍、毕竟如果是初学者不是很容易就能理解的。可以用笔记下几个关键的状态，并且看看你有没有真正的投入去看，独立去思考了。</span></p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; "><br /><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; ">import</span><span style="color: #000000; ">&nbsp;java.io.BufferedReader;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;java.io.IOException;<br /></span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;java.io.InputStreamReader;<br /><br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;Hanoi&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="color: #0000FF; ">throws</span><span style="color: #000000; ">&nbsp;IOException{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;n;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BufferedReader&nbsp;buf;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;BufferedReader(</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;InputStreamReader(System.in));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Please&nbsp;input&nbsp;the&nbsp;number&nbsp;of&nbsp;disk&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Integer.parseInt(buf.readLine());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Hanoi&nbsp;hanoi&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Hanoi();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hanoi.move(n,</span><span style="color: #000000; ">'</span><span style="color: #000000; ">A</span><span style="color: #000000; ">'</span><span style="color: #000000; ">,</span><span style="color: #000000; ">'</span><span style="color: #000000; ">B</span><span style="color: #000000; ">'</span><span style="color: #000000; ">,</span><span style="color: #000000; ">'</span><span style="color: #000000; ">C</span><span style="color: #000000; ">'</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">public</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;move(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;n,&nbsp;</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">&nbsp;a,&nbsp;</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">&nbsp;b,&nbsp;</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">&nbsp;c){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(n&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Disk&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;n&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;From&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;a&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;To&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;c);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;move(n</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,a,c,b);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Disk&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;n&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;From&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;a&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;To&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;c);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;move(n</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,b,a,c);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /></span></div></p><div style="margin-top: 5px; margin-right: 0px; margin-bottom: 5px; margin-left: 0px; background-color: #faf7ef; font-size: 12px; color: #393939; text-align: left; "><div style="margin-top: 5px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 0px; line-height: 1.5; "></span></div></div><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">&nbsp;</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">以上、如果有不对的地方、还希望您能指出。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">我对递归的一点理解：</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">解决实际问题时、不能太去关心实现的细节（因为递归的过程恰恰是我们实现的方法）就像这个问题，如在第一步就过多的纠结于如何把n-1个盘子移动到B上、那么你的思路就很难继续深入。只要看做是用函数实现就好，如果你能看出不管怎么移动，其实本质都一样的时候，那么就能较快的得到结果了。就像这个案例，要注意到我们做的关键几步都只是移动的顺序有改变，其中的规则没有改变，如</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">如果用函数表示的话，就只是参数调用的顺序有所不同了。在递归的运用中、不用关心每一步的具体实现&nbsp;，只要看做用一个函数表示就好。分析问题的时候，最好画出自己的推理过程，得到有效的状态图。</p><p style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; color: #393939; font-family: verdana, 'ms song', Arial, Helvetica, sans-serif; text-align: left; background-color: #faf7ef; ">思考问题讲求思路的连贯性、力求尽快进入状态，享受完全投入到一件事中的美妙感觉</p><img src ="http://www.blogjava.net/czihong/aggbug/386673.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/czihong/" target="_blank">Chan Chen</a> 2012-08-31 11:31 <a href="http://www.blogjava.net/czihong/articles/386673.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Dijkstra's algorithm</title><link>http://www.blogjava.net/czihong/articles/382323.html</link><dc:creator>Chan Chen</dc:creator><author>Chan Chen</author><pubDate>Thu, 05 Jul 2012 22:33:00 GMT</pubDate><guid>http://www.blogjava.net/czihong/articles/382323.html</guid><wfw:comment>http://www.blogjava.net/czihong/comments/382323.html</wfw:comment><comments>http://www.blogjava.net/czihong/articles/382323.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/czihong/comments/commentRss/382323.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/czihong/services/trackbacks/382323.html</trackback:ping><description><![CDATA[<p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "></p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "><a href="http://renaud.waldura.com/doc/java/dijkstra/">http://renaud.waldura.com/doc/java/dijkstra/</a>&nbsp;<br /><br />Dijkstra's algorithm is probably the best-known and thus most implemented shortest path algorithm. It is simple, easy to understand and implement, yet impressively efficient. By getting familiar with such a sharp tool, a developer can solve efficiently and elegantly problems that would be considered impossibly hard otherwise. Be my guest as I explore a possible implementation of Dijkstra's shortest path algorithm in Java.</p><h2>What It Does</h2><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Dijkstra's algorithm, when applied to a graph, quickly finds the shortest path from a chosen source to a given destination. (The question "how quickly" is answered later in this article.) In fact, the algorithm is so powerful that it finds all shortest paths from the source to all destinations! This is known as the&nbsp;<em>single-source</em>&nbsp;shortest paths problem. In the process of finding all shortest paths to all destinations, Dijkstra's algorithm will also compute, as a side-effect if you will, a&nbsp;<cite>spanning tree</cite>&nbsp;for the graph. While an interesting result in itself, the spanning tree for a graph can be found using lighter (more efficient) methods than Dijkstra's.</p><h2>How It Works</h2><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">First let's start by defining the entities we use. The graph is made of&nbsp;<em>vertices</em>&nbsp;(or nodes, I'll use both words interchangeably), and&nbsp;<em>edges</em>&nbsp;which link vertices together. Edges are directed and have an associated&nbsp;<em>distance</em>, sometimes called the weight or the cost. The distance between the vertex&nbsp;<var>u</var>&nbsp;and the vertex&nbsp;<var>v</var>&nbsp;is noted [<var>u</var>,&nbsp;<var>v</var>] and is always positive.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "><img src="http://renaud.waldura.com/doc/java/dijkstra/dijkstra-1.gif" alt="" /></p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Dijkstra's algorithm partitions vertices in two distinct sets, the set of&nbsp;<em>unsettled</em>&nbsp;vertices and the set of&nbsp;<em>settled</em>&nbsp;vertices. Initially all vertices are unsettled, and the algorithm ends once all vertices are in the settled set. A vertex is considered settled, and moved from the unsettled set to the settled set, once its shortest distance from the source has been found.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">We all know that&nbsp;<cite>algorithm + data structures = programs</cite>, in the famous words of Niklaus Wirth. The following data structures are used for this algorithm:</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "><table cellpadding="6"><tbody><tr><th>d</th><td>stores the best estimate of the shortest distance from the source to each vertex</td></tr><tr><th>&#960;</th><td>stores the predecessor of each vertex on the shortest path from the source</td></tr><tr><th>S</th><td>the set of settled vertices, the vertices whose shortest distances from the source have been found</td></tr><tr><th>Q</th><td>the set of unsettled vertices</td></tr></tbody></table></p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">With those definitions in place, a high-level description of the algorithm is deceptively simple. With&nbsp;<var>s</var>&nbsp;as the source vertex:<br /><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; font-size: 12pt;">//</span><span style="color: #008000; font-size: 12pt;">&nbsp;initialize&nbsp;d&nbsp;to&nbsp;infinity,&nbsp;&#960;&nbsp;and&nbsp;Q&nbsp;to&nbsp;empty&nbsp;d&nbsp;=&nbsp;(&nbsp;&#8734;&nbsp;)&nbsp;&#960;&nbsp;=&nbsp;()&nbsp;S&nbsp;=&nbsp;Q&nbsp;=&nbsp;()&nbsp;&nbsp;add&nbsp;s&nbsp;to&nbsp;Q&nbsp;d(s)&nbsp;=&nbsp;0&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #0000ff; font-size: 12pt;">while</span><span style="font-size: 12pt;">&nbsp;Q&nbsp;is&nbsp;not&nbsp;empty&nbsp;{</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u&nbsp;</span><span style="font-size: 12pt;">=</span><span style="font-size: 12pt;">&nbsp;extract</span><span style="font-size: 12pt;">-</span><span style="font-size: 12pt;">minimum(Q)</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;u&nbsp;to&nbsp;S</span><br /><span style="font-size: 12pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;relax</span><span style="font-size: 12pt;">-</span><span style="font-size: 12pt;">neighbors(u)</span><br /><span style="font-size: 12pt;">&nbsp;}&nbsp;</span></div></p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Dead simple isn't it? The two procedures called from the main loop are defined below:<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 />-->relax-neighbors(u)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;each&nbsp;vertex&nbsp;v&nbsp;adjacent&nbsp;to&nbsp;u,&nbsp;v&nbsp;not&nbsp;in&nbsp;S<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;d(v)&nbsp;&gt;&nbsp;d(u)&nbsp;+&nbsp;[u,v]<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;a&nbsp;shorter&nbsp;distance&nbsp;exists</span><span style="color: #008000; "><br /></span>&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;d(v)&nbsp;=&nbsp;d(u)&nbsp;+&nbsp;[u,v]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#960;(v)&nbsp;=&nbsp;u<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add&nbsp;v&nbsp;to&nbsp;Q<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;}<br /><br />&nbsp;&nbsp;extract-minimum(Q)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;find&nbsp;the&nbsp;smallest&nbsp;(as&nbsp;defined&nbsp;by&nbsp;d)&nbsp;vertex&nbsp;in&nbsp;Q<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remove&nbsp;it&nbsp;from&nbsp;Q&nbsp;and&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;it<br />&nbsp;}&nbsp;</div><h3><br />An Example</h3><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">So far I've listed the instructions that make up the algorithm. But to really understand it, let's follow the algorithm on an example. We shall run Dikjstra's shortest path algorithm on the following graph, starting at the source vertex&nbsp;<var>a</var>.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "><img src="http://renaud.waldura.com/doc/java/dijkstra/dijkstra-2.gif" alt="" /></p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">We start off by adding our source vertex&nbsp;<var>a</var>&nbsp;to the set&nbsp;<var>Q</var>.&nbsp;<var>Q</var>&nbsp;isn't empty, we extract its minimum,&nbsp;<var>a</var>&nbsp;again. We add&nbsp;<var>a</var>&nbsp;to&nbsp;<var>S</var>, then relax its neighbors. (I recommend you follow the algorithm in parallel with this explanation.)</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "><img src="http://renaud.waldura.com/doc/java/dijkstra/dijkstra-2a.gif" alt="" /></p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Those neighbors, vertices adjacent to&nbsp;<var>a</var>, are&nbsp;<var>b</var>&nbsp;and&nbsp;<var>c</var>&nbsp;(in green above). We first compute the best distance estimate from&nbsp;<var>a</var>&nbsp;to&nbsp;<var>b</var>.&nbsp;<var>d</var>(<var>b</var>) was initialized to infinity, therefore we do:</p><pre style="line-height: normal; background-color: #faf8f0; ">d(b) = d(a) + [a,b] = 0 + 4 = 4</pre><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">&#960;</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">(</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">b</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">) is set to&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">a</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">, and we add&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">b</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">&nbsp;to&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Q</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">. Similarily for&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">c</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">, we assign&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">d</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">(</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">c</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">) to 2, and&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">&#960;</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">(</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">c</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">) to&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">a</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">. Nothing tremendously exciting so far.</span><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">The second time around,&nbsp;<var>Q</var>&nbsp;contains&nbsp;<var>b</var>&nbsp;and&nbsp;<var>c</var>. As seen above,&nbsp;<var>c</var>&nbsp;is the vertex with the current shortest distance of 2. It is extracted from the queue and added to&nbsp;<var>S</var>, the set of settled nodes. We then relax the neighbors of&nbsp;<var>c</var>, which are&nbsp;<var>b</var>,&nbsp;<var>d</var>&nbsp;and&nbsp;<var>a</var>.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "><img src="http://renaud.waldura.com/doc/java/dijkstra/dijkstra-2c.gif" alt="" /></p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "><var>a</var>&nbsp;is ignored because it is found in the settled set. But it gets interesting: the first pass of the algorithm had concluded that the shortest path from&nbsp;<var>a</var>&nbsp;to&nbsp;<var>b</var>&nbsp;was direct. Looking at&nbsp;<var>c</var>'s neighbor&nbsp;<var>b</var>, we realize that:</p><pre style="line-height: normal; background-color: #faf8f0; ">d(b) = 4 &gt; d(c) + [c,b] = 2 + 1 = 3</pre><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Ah-ah! We have found that a shorter path going through&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">c</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">&nbsp;exists between&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">a</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">&nbsp;and&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">b</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">.&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">d</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">(</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">b</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">) is updated to 3, and&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">&#960;</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">(</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">b</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">) updated to&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">c</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">.&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">b</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">&nbsp;is added again to&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Q</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">. The next adjacent vertex is&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">d</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">, which we haven't seen yet.&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">d</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">(</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">d</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">) is set to 7 and&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">&#960;</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">(</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">d</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">) to&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">c</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">.</span><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">The unsettled vertex with the shortest distance is extracted from the queue, it is now&nbsp;<var>b</var>. We add it to the settled set and relax its neighbors&nbsp;<var>c</var>&nbsp;and&nbsp;<var>d</var>.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "><img src="http://renaud.waldura.com/doc/java/dijkstra/dijkstra-2b.gif" alt="" /></p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">We skip&nbsp;<var>c</var>, it has already been settled. But a shorter path is found for&nbsp;<var>d</var>:</p><pre style="line-height: normal; background-color: #faf8f0; ">d(d) = 7 &gt; d(b) + [b,d] = 3 + 1 = 4</pre><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Therefore we update&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">d</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">(</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">d</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">) to 4 and&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">&#960;</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">(</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">d</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">) to&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">b</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">. We add&nbsp;</span><var style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">d</var><span style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">&nbsp;to the Q set.</span><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">At this point the only vertex left in the unsettled set is&nbsp;<var>d</var>, and all its neighbors are settled. The algorithm ends. The final results are displayed in red below:</p><ul style="font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "><li style="text-align: justify; "><var>&#960;</var>&nbsp;- the shortest path, in predecessor fashion</li><li style="text-align: justify; "><var>d</var>&nbsp;- the shortest distance from the source for each vertex</li></ul><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "><img src="http://renaud.waldura.com/doc/java/dijkstra/dijkstra-3.gif" alt="" /></p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">This completes our description of Dijkstra's shortest path algorithm. Other shortest path algorithms exist (see the References section at the end of this article), but Dijkstra's is one of the simplest, while still offering good performance in most cases.</p><h2>Implementing It in Java</h2><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">The Java implementation is quite close to the high-level description we just walked through. For the purpose of this article, my Java implementation of Dijkstra's shortest path finds shortest routes between cities on a map. The&nbsp;<code>RoutesMap</code>&nbsp;object defines a weighted, oriented graph as defined in the introduction section of this article.<br /><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; ">interface</span>&nbsp;RoutesMap&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getDistance(City&nbsp;start,&nbsp;City&nbsp;end);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;City&gt;&nbsp;getDestinations(City&nbsp;city);<br />&nbsp;}&nbsp;</div><p>&nbsp;</p><h3>Data Structures</h3><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">We've listed above the data structures used by the algorithm, let's now decide how we are going to implement them in Java.</p><h4>S, the settled nodes set</h4><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">This one is quite straightforward. The Java Collections feature the&nbsp;<a href="http://java.sun.com/j2se/1.5/docs/api/java/util/Set.html"><code>Set</code></a>&nbsp;interface, and more precisely, the&nbsp;<a href="http://java.sun.com/j2se/1.5/docs/api/java/util/HashSet.html"><code>HashSet</code></a>&nbsp;implementation which offers constant-time performance on the&nbsp;<a href="http://java.sun.com/j2se/1.5/docs/api/java/util/HashSet.html#contains(java.lang.Object)"><code>contains</code></a>&nbsp;operation, the only one we need. This defines our first data structure.<br /><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; ">final</span>&nbsp;Set&lt;City&gt;&nbsp;settledNodes&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;HashSet&lt;City&gt;();<br />&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;isSettled(City&nbsp;v)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;settledNodes.contains(v);<br />&nbsp;}&nbsp;</div><p>&nbsp;</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Notice how my data structure is declared as an abstract type (<code>Set</code>) instead of a concrete type (<code>HashSet</code>). Doing so is a good software engineering practice, as it allows to change the actual type of the collection without any modification to the code that uses it.</p><h4>d, the shortest distances list</h4><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">As we've seen, one output of Dijkstra's algorithm is a list of shortest distances from the source node to all the other nodes in the graph. A straightforward way to implement this in Java is with a&nbsp;<a href="http://java.sun.com/j2se/1.5/docs/api/java/util/Map.html"><code>Map</code></a>, used to keep the shortest distance value for every node. We also define two accessors for readability, and to encapsulate the default infinite distance.<br /><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; ">final</span>&nbsp;Map&lt;City,&nbsp;Integer&gt;&nbsp;shortestDistances&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;HashMap&lt;City,&nbsp;Integer&gt;();<br />&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setShortestDistance(City&nbsp;city,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;distance)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shortestDistances.put(city,&nbsp;distance);<br />&nbsp;}<br /><br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getShortestDistance(City&nbsp;city)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Integer&nbsp;d&nbsp;=&nbsp;shortestDistances.get(city);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;(d&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;?&nbsp;INFINITE_DISTANCE&nbsp;:&nbsp;d;<br />}&nbsp;</div><p>&nbsp;</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">You may notice I declare this field&nbsp;<code>final</code>. This is a Java idiom used to flag aggregation relationships between objects. By marking a field&nbsp;<code>final</code>, I am able to convey that it is part of a aggregation relationship, enforced by the properties of&nbsp;<code>final</code>&#8212;the encapsulating class cannot exist without this field.</p><h4>&#960;, the predecessors tree</h4><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Another output of the algorithm is the predecessors tree, a tree spanning the graph which yields the actual shortest paths. Because this is the&nbsp;<em>predecessors</em>&nbsp;tree, the shortest paths are actually stored in reverse order, from destination to source. Reversing a given path is easy with&nbsp;<a href="http://java.sun.com/j2se/1.5/docs/api/java/util/Collections.html#reverse(java.util.List)"><code>Collections.reverse()</code></a>.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">The predecessors tree stores a relationship between two nodes, namely a given node's predecessor in the spanning tree. Since this relationship is one-to-one, it is akin to a<em>mapping</em>&nbsp;between nodes. Therefore it can be implemented with, again, a&nbsp;<a href="http://java.sun.com/j2se/1.5/docs/api/java/util/Map.html"><code>Map</code></a>. We also define a pair of accessors for readability.<br /><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; ">final</span>&nbsp;Map&lt;City,&nbsp;City&gt;&nbsp;predecessors&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;HashMap&lt;City,&nbsp;City&gt;();<br /><span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setPredecessor(City&nbsp;a,&nbsp;City&nbsp;b)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;predecessors.put(a,&nbsp;b);<br />&nbsp;}<br /><br /><span style="color: #0000FF; ">public</span>&nbsp;City&nbsp;getPredecessor(City&nbsp;city)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;predecessors.get(city);<br />}&nbsp;</div><p>&nbsp;</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Again I declare my data structure to be of the abstract type&nbsp;<code>Map</code>, instead of the concrete type&nbsp;<code>HashMap</code>. And tag it&nbsp;<code>final</code>&nbsp;as well.</p><h4>Q, the unsettled nodes set</h4><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">As seen in the previous section, a data structure central to Dijkstra's algorithm is the set of unsettled vertices&nbsp;<var>Q</var>. In Java programming terms, we need a structure able to store the nodes of our example graph, i.e.&nbsp;<code>City</code>&nbsp;objects. That structure is then looked up for the city with the current shortest distance given by&nbsp;<var>d</var>().</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">We could do this by using another&nbsp;<code>Set</code>&nbsp;of cities, and sort it according to&nbsp;<var>d</var>() to find the city with shortest distance every time we perform this operation. This isn't complicated, and we could leverage&nbsp;<a href="http://java.sun.com/j2se/1.5/docs/api/java/util/Collections.html#min(java.util.Collection,%20java.util.Comparator)"><code>Collections.min()</code></a>&nbsp;using a custom&nbsp;<code>Comparator</code>&nbsp;to compare the elements according to&nbsp;<var>d</var>().</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">But because we do this at every iteration, a smarter way would be to keep the set ordered at all times. That way all we need to do to get the city with the lowest distance is to get the first element in the set. New elements would need to be inserted in the right place, so that the set is always kept ordered.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">A quick search through the Java collections API yields the&nbsp;<a href="http://java.sun.com/j2se/1.5/docs/api/java/util/PriorityQueue.html"><code>PriorityQueue</code></a>: it can sort elements according to a custom comparator, and provides constant-time access to the smallest element. This is precisely what we need, and we'll write a comparator to order cities (the set elements) according to the current shortest distance. Such a comparator is included below, along with the&nbsp;<code>PriorityQueue</code>&nbsp;definition. Also listed is the small method that extracts the node with the shortest distance.<br /><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; ">final</span>&nbsp;Comparator&lt;City&gt;&nbsp;shortestDistanceComparator&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Comparator&lt;City&gt;()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;compare(City&nbsp;left,&nbsp;City&nbsp;right)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;shortestDistanceLeft&nbsp;=&nbsp;getShortestDistance(left);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;shortestDistanceRight&nbsp;=&nbsp;getShortestDistance(right);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(shortestDistanceLeft&nbsp;&gt;&nbsp;shortestDistanceRight)<br />&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;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;+1;<br />&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;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(shortestDistanceLeft&nbsp;&lt;&nbsp;shortestDistanceRight)<br />&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;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;-1;<br />&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;<span style="color: #0000FF; ">else</span>&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;equal</span><span style="color: #008000; "><br /></span>&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;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;left.compareTo(right);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;PriorityQueue&lt;City&gt;&nbsp;unsettledNodes&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;PriorityQueue&lt;City&gt;(INITIAL_CAPACITY,&nbsp;shortestDistanceComparator);<br />&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;City&nbsp;extractMin()<br />&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;unsettledNodes.poll();<br />&nbsp;}&nbsp;</div><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">One important note about the comparator: it is used by the&nbsp;<code>PriorityQueue</code>&nbsp;to determine both object ordering and identity. If the comparator returns that two elements are equal, the queue infers they are the same, and it stores only one instance of the element. To prevent losing nodes with equal shortest distances, we must compare the elements themselves (third block in the&nbsp;<code>if</code>&nbsp;statement above).</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">Having powerful, flexible data structures at our disposal is what makes Java such an enjoyable language (that, and garbage collection of course).</p><h3>Putting It All Together</h3><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">We have defined our data structures, we understand the algorithm, all that remains to do is implement it. As I mentioned earlier, my implementation is close to the high-level description given above. Note that when the only shortest path between two specific nodes is asked, the algorithm can be interrupted as soon as the destination node is reached.<br /><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;execute(City&nbsp;start,&nbsp;City&nbsp;destination)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;initDijkstra(start);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">while</span>&nbsp;(!unsettledNodes.isEmpty())&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;get&nbsp;the&nbsp;node&nbsp;with&nbsp;the&nbsp;shortest&nbsp;distance</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;City&nbsp;u&nbsp;=&nbsp;extractMin();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;destination&nbsp;reached,&nbsp;stop</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(u&nbsp;==&nbsp;destination)&nbsp;<span style="color: #0000FF; ">break</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;settledNodes.add(u);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;relaxNeighbors(u);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;}&nbsp;</div><p>&nbsp;</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">The&nbsp;<code>DijkstraEngine</code>&nbsp;class implements this algorithm and brings it all together. See "Implementation Notes" below to download the source code.</p><h2>A Word About Performance</h2><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">The complexity of Dijkstra's algorithm depends heavily on the complexity of the priority queue&nbsp;<var>Q</var>. If this queue is implemented naively as I first introduced it (i.e. it is re-ordered at every iteration to find the mininum node), the algorithm performs in O(<var>n</var><sup>2</sup>), where&nbsp;<var>n</var>&nbsp;is the number of nodes in the graph.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">With a real priority queue kept ordered at all times, as we implemented it, the complexity averages O(<var>n</var>&nbsp;log&nbsp;<var>m</var>). The logarithm function stems from the collections<code>PriorityQueue</code>&nbsp;class, a heap implementation which performs in log(<var>m</var>).</p><h2>Implementation Notes</h2><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">The Java source code discussed in this article is&nbsp;<a href="http://renaud.waldura.com/doc/java/dijkstra/renaud-waldura-dijkstra.zip">available for download as a ZIP file</a>. Extensive unit tests are provided and validate the correctness of the implementation. Some minimal Javadoc is also provided. As the code makes use of the&nbsp;<code>assert</code>&nbsp;facility and generics, it must be compiled with "<code>javac -source 1.5</code>"; the tests require&nbsp;<code>junit.jar</code>.<a href="http://renaud.waldura.com/doc/java/eclipse-ten-reasons.shtml">I warmly recommend Eclipse</a>&nbsp;for all Java development.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">I've received a fair amount of e-mail about this article, which has become quite popular. I'm unfortunately unable to answer all your questions, and for this I apologize. Keep in mind this article (and the code) is meant as a starting point: the implementation discussed here is hopefully simple, correct, and relatively easy to understand, but is probably not suited to your specific problem. You must tailor it to your own domain.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; ">My goal in writing this article was to share and teach a useful tool, striving for 1- simplicity and 2- correctness. I purposefully shied away from turning this exercise into a full-blown generic Java implementation. Readers after full-featured, industrial-strength Java implementations of Dijkstra's shortest path algorithm should look at the "Resources" section below.</p><p style="text-align: justify; font-family: 'Times New Roman'; line-height: normal; background-color: #faf8f0; font-size: medium; "></p><img src ="http://www.blogjava.net/czihong/aggbug/382323.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/czihong/" target="_blank">Chan Chen</a> 2012-07-06 06:33 <a href="http://www.blogjava.net/czihong/articles/382323.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Bag Queue and Stack</title><link>http://www.blogjava.net/czihong/articles/382321.html</link><dc:creator>Chan Chen</dc:creator><author>Chan Chen</author><pubDate>Thu, 05 Jul 2012 21:28:00 GMT</pubDate><guid>http://www.blogjava.net/czihong/articles/382321.html</guid><wfw:comment>http://www.blogjava.net/czihong/comments/382321.html</wfw:comment><comments>http://www.blogjava.net/czihong/articles/382321.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/czihong/comments/commentRss/382321.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/czihong/services/trackbacks/382321.html</trackback:ping><description><![CDATA[<p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; ">Several fundamental data types involve collections of objects. Specifically, the set of values is a collection of objects, and the operations revolve around adding, removing, or examining objects in the collection. In this section, we consider three such data types, known as the bag, the queue, and the stack. They differ in the specification of which object is to be removed or examined next.</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "></p><h2>APIs.</h2><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">&nbsp;We define the APIs for bags, queues, and stacks. Beyond the basics, these APIs reflect two Java features: generics and iterable collections.</span><img src="http://algs4.cs.princeton.edu/13stacks/images/collection-apis.png" alt="APIs for bag, queue, and stack" style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px;" /><ul style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><p style="margin-top: 10px; margin-bottom: 0px; "></p><li style="margin-top: 6px; list-style: disc; "><em>Generics.</em>&nbsp;An essential characteristic of collection ADTs is that we should be able to use them for any type of data. A specific Java mechanism known as&nbsp;<em>generics</em>&nbsp;enables this capability. The notation&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">&lt;Item&gt;</tt>&nbsp;after the class name in each of our APIs defines the name&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Item</tt>&nbsp;as a&nbsp;<em>type parameter</em>, a symbolic placeholder for some concrete type to be used by the client. You can read&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Stack&lt;Item&gt;</tt>&nbsp;as "stack of items." For example, you can write code such as<blockquote style="margin-left: 40px; margin-right: 0px; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">Stack&lt;String&gt; stack = new Stack&lt;String&gt;(); <br />stack.push("Test"); <br />... <br />String next = stack.pop();  </pre></td></tr></tbody></table></blockquote>to use a stack for&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">String</tt>&nbsp;objects.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Autoboxing.</em>&nbsp;Type parameters have to be instantiated as reference types, so Java automatically converts between a primitive type and its corresponding wrapper type in assignments, method arguments, and arithmetic/logic expressions. This conversion enables us to use generics with primitive types, as in the following code:<blockquote style="margin-left: 40px; margin-right: 0px; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">Stack&lt;Integer&gt; stack = new Stack&lt;Integer&gt;(); stack.push(17);<br />// auto-boxing (int -&gt; Integer) int i = stack.pop();<br />// auto-unboxing (Integer -&gt; int) </pre></td></tr></tbody></table></blockquote>Automatically casting a primitive type to a wrapper type is known as&nbsp;<em>autoboxing</em>, and automatically casting a wrapper type to a primitive type is known as&nbsp;<em>auto-unboxing</em>.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Iterable collections.</em>&nbsp;For many applications, the client's requirement is just to process each of the items in some way, or to&nbsp;<em>iterate</em>&nbsp;through the items in the collection. Java's&nbsp;<em>foreach</em>&nbsp;statement supports this paradigm. For example, suppose that&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">collection</tt>&nbsp;is a&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Queue&lt;Transaction&gt;</tt>. Then, if the collection is iterable, the client can print a transaction list with a single statement:<blockquote style="margin-left: 40px; margin-right: 0px; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">for (Transaction t : collection)<br />    StdOut.println(t); </pre></td></tr></tbody></table></blockquote><p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Bags.</em>&nbsp;A&nbsp;<em>bag</em>&nbsp;is a collection where removing items is not supported&#8212;its purpose is to provide clients with the ability to collect items and then to iterate through the collected items.&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/Stats.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">Stats.java</a>&nbsp;is a bag client that reads a sequence of real numbers from standard input and prints out their mean and standard deviation.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>FIFO queues.</em>&nbsp;A&nbsp;<em>FIFO queue</em>&nbsp;is a collection that is based on the&nbsp;<em>first-in-first-out</em>&nbsp;(FIFO) policy. The policy of doing tasks in the same order that they arrive server is one that we encounter frequently in everyday life: from people waiting in line at a theater, to cars waiting in line at a toll booth, to tasks waiting to be serviced by an application on your computer.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Pushdown stack.</em>&nbsp;A&nbsp;<em>pushdown stack</em>&nbsp;is a collection that is based on the&nbsp;<em>last-in-first-out</em>&nbsp;(LIFO) policy. When you click a hyperlink, your browser displays the new page (and pushes onto a stack). You can keep clicking on hyperlinks to visit new pages, but you can always revisit the previous page by clicking the back button (popping it from the stack).&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/Reverse.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">Reverse.java</a>&nbsp;is a stack client that reads a sequence of integers from standard input and prints them in reverse order.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Arithmetic expression evaluation.</em>&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/Evaluate.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">Evaluate.java</a>&nbsp;is a stack client that evaluates fully parenthesized arithmetic expressions. It uses Dijkstra's 2-stack algorithm:<ul><li style="margin-top: 6px; list-style: circle; ">Push operands onto the operand stack.</li><li style="margin-top: 6px; list-style: circle; ">Push operators onto the operator stack.</li><li style="margin-top: 6px; list-style: circle; ">Ignore left parentheses.</li><li style="margin-top: 6px; list-style: circle; ">On encountering a right parenthesis, pop an operator, pop the requisite number of operands, and push onto the operand stack the result of applying that operator to those operands.</li></ul><p style="margin-top: 10px; margin-bottom: 0px; ">This code is a simple example of an&nbsp;<em>interpreter</em>.</p></li></ul><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "></p><h2>Array and resizing array implementations of collections.</h2><ul style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><p style="margin-top: 10px; margin-bottom: 0px; "></p><li style="margin-top: 6px; list-style: disc; "><em>Fixed-capacity stack of strings.</em>&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/FixedCapacityStackOfStrings.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">FixedCapacityStackOfString.java</a>&nbsp;implements a fixed-capacity stack of strings using an array.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Fixed-capacity generic stack.</em>&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/FixedCapacityStack.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">FixedCapacityStack.java</a>&nbsp;implements a generic fixed-capacity stack.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Array resizing stack.</em>&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/ResizingArrayStack.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">ResizingArrayStack.java</a>&nbsp;implements a generic stack using a&nbsp;<em>resizing array</em>. With a resizing array, we dynamically adjust the size of the array so that it is both sufficiently large to hold all of the items and not so large as to waste an excessive amount of space. We<em>double</em>&nbsp;the size of the array in&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">push()</tt>&nbsp;if it is full; we&nbsp;<em>halve</em>&nbsp;the size of the array in&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">pop()</tt>&nbsp;if it is less than one-quarter full.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Array resizing queue.</em>&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/ResizingArrayQueue.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">ResizingArrayQueue.java</a>&nbsp;implements the queue API with a resizing array.</li></ul><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "></p><h2>Linked lists.</h2><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">&nbsp;A&nbsp;</span><em style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">linked list</em><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">&nbsp;is a recursive data structure that is either empty (</span><em style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">null</em><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">) or a reference to a&nbsp;</span><em style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">node</em><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">&nbsp;having a generic item and a reference to a linked list. To implement a linked list, we start with a&nbsp;</span><em style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">nested class</em><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">&nbsp;that defines the node abstraction</span><blockquote style="margin-left: 40px; margin-right: 0px; color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">private class Node {<br />    Item item;<br />    Node next;<br /> } </pre></td></tr></tbody></table></blockquote><ul style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><p style="margin-top: 10px; margin-bottom: 0px; "></p><li style="margin-top: 6px; list-style: disc; "><em>Building a linked list.</em>&nbsp;To build a linked list that contains the items&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">to</tt>,&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">be</tt>, and&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">or</tt>, we create a&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Node</tt>&nbsp;for each item, set the item field in each of th<img src="http://algs4.cs.princeton.edu/13stacks/images/linked-list.png" alt="building a linked list" /><p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Insert at the beginning.</em>&nbsp;The easiest place to insert a new node in a linked list is at the beginning.<img src="http://algs4.cs.princeton.edu/13stacks/images/linked-list-insert-front.png" alt="inserting a new node at the beginning of a linked list" /><p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Remove from the beginning.</em>&nbsp;Removing the first node in a linked list is also easy.<br /><img src="http://algs4.cs.princeton.edu/13stacks/images/linked-list-remove-first.png" alt="removing the first node in a linked list" /><p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Insert at the end.</em>&nbsp;To insert a node at the end of a linked list, we maintain a link to the last node in the list.<img src="http://algs4.cs.princeton.edu/13stacks/images/linked-list-insert-end.png" alt="inserting a node at the end of a linked list" /><p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Traversal.</em>&nbsp;The following is the idiom for traversing the nodes in a linked list.<blockquote style="margin-left: 40px; margin-right: 0px; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">for (Node x = first; x != null; x = x.next) {<br />    // process x.item<br /> } </pre></td></tr></tbody></table></blockquote></li></ul><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "></p><h2>Linked-list implementations of collections.</h2><ul style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><p style="margin-top: 10px; margin-bottom: 0px; "></p><li style="margin-top: 6px; list-style: disc; "><em>Linked list implementation of a stack.</em>&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/Stack.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">Stack.java</a>&nbsp;implements a generic stack using a linked list. It maintains the stack as a linked list, with the top of the stack at the beginning, referenced by an instance variable&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">first</tt>. To&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">push()</tt>&nbsp;an item, we add it to the beginning of the list; to&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">pop()</tt>an item, we remove it from the beginning of the list.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Linked list implementation of a queue.</em>&nbsp;Program&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/Queue.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">Queue.java</a>&nbsp;implements a generic FIFO queue using a linked list. It maintains the queue as a linked list in order from least recently to most recently added items, with the beginning of the queue referenced by an instance variable&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">first</tt>and the end of the queue referenced by an instance variable&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">last</tt>. To&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">enqueue()</tt>&nbsp;an item, we add it to the end of the list; to&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">dequeue()</tt>&nbsp;an item, we remove it from the beginning of the list.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; "><em>Linked list implementation of a bag.</em>&nbsp;Program&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/Bag.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">Bag.java</a>&nbsp;implements a generic bag using a linked list. The implementation is the same as&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/Stack.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">Stack.java</a>except for changing the name of&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">push()</tt>&nbsp;to&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">add()</tt>&nbsp;and removing&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">pop()</tt>.</li></ul><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "></p><h2>Iteration.</h2><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">&nbsp;To consider the task of implementing iteration, we start with a snippet of client code that prints all of the items in a collection of strings, one per line:</span><blockquote style="margin-left: 40px; margin-right: 0px; color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">Stack&lt;String&gt; collection = new Stack&lt;String&gt;(); <br />... <br />for (String s : collection)<br />    StdOut.println(s);<br /> &nbsp;&nbsp;&nbsp;... </pre></td></tr></tbody></table></blockquote><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">This&nbsp;</span><em style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">foreach</em><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">&nbsp;statement is shorthand for the following&nbsp;</span><tt style="font-family: 'courier new', courier, mono; color: #221e1f; line-height: 16px; background-color: #ffffff; ">while</tt><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">&nbsp;statement:</span><blockquote style="margin-left: 40px; margin-right: 0px; color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">Iterator&lt;String&gt; i = collection.iterator(); <br />while (i.hasNext()) {<br />     String s = i.next();<br />    StdOut.println(s);<br /> } </pre></td></tr></tbody></table></blockquote><span style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; ">To implement iteration in a collection:</span><ul style="color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><p style="margin-top: 10px; margin-bottom: 0px; "></p><li style="margin-top: 6px; list-style: disc; ">Include the following&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">import</tt>&nbsp;statement so that our code can refer to Java's&nbsp;<a href="http://download.oracle.com/javase/6/docs/api/java/util/Iterator.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">java.util.Iterator</a>&nbsp;interface:<blockquote style="margin-left: 40px; margin-right: 0px; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">import java.util.Iterator; </pre></td></tr></tbody></table></blockquote><p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; ">Add the following to the class declaration, a promise to provide an&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">iterator()</tt>&nbsp;method, as specified in the&nbsp;<a href="http://download.oracle.com/javase/6/docs/api/java/lang/Iterable.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">java.lang.Iterable</a>&nbsp;interface:<blockquote style="margin-left: 40px; margin-right: 0px; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">implements Iterable&lt;Item&gt; </pre></td></tr></tbody></table></blockquote><p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; ">Implement a method&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">iterator()</tt>&nbsp;that returns an object from a class that implements the&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Iterator</tt>&nbsp;interface:<blockquote style="margin-left: 40px; margin-right: 0px; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">public Iterator&lt;Item&gt; iterator() {<br />     return new ListIterator();<br /> } </pre></td></tr></tbody></table></blockquote><p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: disc; ">Implement a nested class that implements the&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Iterator</tt>&nbsp;interface by including the methods&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">hasNext()</tt>,&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">next()</tt>, and&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">remove()</tt>. We always use an empty method for the optional&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">remove()</tt>&nbsp;method because interleaving iteration with operations that modify the data structure is best avoided.<ul><p style="margin-top: 10px; margin-bottom: 0px; "></p><li style="margin-top: 6px; list-style: circle; ">The nested class&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">ListIterator</tt>&nbsp;in&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/Bag.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">Bag.java</a>&nbsp;illustrates how to implement a class that implements the&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Iterator</tt>&nbsp;interface when the underlying data structure is a linked list.<p style="margin-top: 10px; margin-bottom: 0px; "></p></li><li style="margin-top: 6px; list-style: circle; ">The nested class&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">ArrayIterator</tt>&nbsp;in&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/ArrayResizingBag.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">ArrayResizingBag.java</a>&nbsp;does the same when the underlying data structure is an array.</li></ul></li></ul><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><br /></p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "></p><h4>Autoboxing Q + A</h4><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>Q.</strong>&nbsp;How does auto-boxing handle the following code fragment?</p><blockquote style="margin-left: 40px; margin-right: 0px; color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">Integer a = null; int b = a; </pre></td></tr></tbody></table></blockquote><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>A.</strong>&nbsp;It results in a run-time error. Primitive type can store every value of their corresponding wrapper type except&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">null</tt>.</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>Q.</strong>&nbsp;Why does the first group of statements print&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">true</tt>, but the second&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">false</tt>?</p><blockquote style="margin-left: 40px; margin-right: 0px; color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">Integer a1 = 100;<br />Integer a2 = 100;<br />System.out.println(a1 == a2);<br />// true  Integer b1 = new Integer(100);<br />Integer b2 = new Integer(100);<br />System.out.println(b1 == b2);<br />// false  Integer c1 = 150;<br />Integer c2 = 150;<br />System.out.println(c1 == c2);<br />// false  </pre></td></tr></tbody></table></blockquote><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>A.</strong>&nbsp;The second prints&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">false</tt>&nbsp;because&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">b1</tt>&nbsp;and&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">b2</tt>&nbsp;are references to different Integer objects. The first and third code fragments rely on autoboxing. Surprisingly the first prints true because values between -128 and 127 appear to refer to the same immutable Integer objects (Java's implementation of&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">valueOf()</tt>&nbsp;retrieves a cached values if the integer is between -128 and 127), while Java constructs new objects for each integer outside this range.</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; ">Here is another&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/Autoboxing.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">Autoboxing.java</a>&nbsp;anomaly.</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "></p><h4>Generics Q + A</h4><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>Q.</strong>&nbsp;Are generics solely for auto-casting?</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>A.</strong>&nbsp;No, but we will use them only for "concrete parameterized types", where each data type is parameterized by a single type. The primary benefit is to discover type mismatch errors at compile-time instead of run-time. There are other more general (and more complicated) uses of generics, including wildcards. This generality is useful for handling subtypes and inheritance. For more information, see this&nbsp;<a href="http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">Generics FAQ</a>&nbsp;and this&nbsp;<a href="http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">generics tutorial</a>.</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>Q.</strong>&nbsp;Can concrete parameterized types be used in the same way as normal types?</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>A.</strong>&nbsp;Yes, with a few exceptions (array creation, exception handling, with&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">instanceof</tt>, and in a class literal).</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>Q.</strong>&nbsp;Why do I get a "can't create an array of generics" error when I try to create an array of generics?</p><blockquote style="margin-left: 40px; margin-right: 0px; color: #221e1f; font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 16px; background-color: #ffffff; "><table><tbody><tr><td style="font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; margin-top: 20px; "><pre style="font-family: 'courier new', courier, mono; font-size: 13px; background-color: #ebebeb; padding: 10px 15px; ">public class ResizingArrayStack&lt;Item&gt; {<br />    Item[] a = new Item[1]; <br />}</pre></td></tr></tbody></table></blockquote><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>A.</strong>&nbsp;Unfortunately, creating arrays of generics is not possible in Java 1.5. The underlying cause is that arrays in Java are&nbsp;<em>covariant</em>, but generics are not. In other words,&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">String[]</tt>&nbsp;is a subtype of&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Object[]</tt>, but&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Stack&lt;String&gt;</tt>&nbsp;is not a subtype of&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Stack&lt;Object&gt;</tt>. To get around this defect, you need to perform an unchecked cast as in&nbsp;<a href="http://algs4.cs.princeton.edu/13stacks/ResizingArrayStack.java.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">ResizingArrayStack.java</a>.</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>Q.</strong>&nbsp;So, why are arrays covariant?</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>A.</strong>&nbsp;Many programmers (and programming language theorists) consider covariant arrays to be a serious defect in Java's type system: they incur unnecessary run-time performance overhead (for example, see&nbsp;<a href="http://download.oracle.com/javase/6/docs/api/java/lang/ArrayStoreException.html" style="font-family: verdana, arial, helvetica, sans-serif; text-decoration: none; ">ArrayStoreException</a>) and can lead to subtle bugs. Covariant arrays were introduced in Java to circumvent the problem that Java didn't originally include generics in its design, e.g., to implement&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">Arrays.sort(Comparable[])</tt>&nbsp;and have it be callable with an input array of type&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">String[]</tt>.</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>Q.</strong>&nbsp;Can I create and return a new array of a parameterized type, e.g., to implement a&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">toArray()</tt>&nbsp;method for a generic queue?</p><p style="font-family: Verdana, arial, helvetica, sans-serif; font-size: 13px; margin-top: 10px; margin-bottom: 0px; color: #221e1f; line-height: 16px; background-color: #ffffff; "><strong>A.</strong>&nbsp;Not easily. You can do it using reflection provided that the client passes an object of the desired concrete type to&nbsp;<tt style="font-family: 'courier new', courier, mono; font-size: 14px; ">toArray()</tt>&nbsp;This is the (awkward) approach taken by Java's Collection Framework.</p><img src ="http://www.blogjava.net/czihong/aggbug/382321.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/czihong/" target="_blank">Chan Chen</a> 2012-07-06 05:28 <a href="http://www.blogjava.net/czihong/articles/382321.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Buffer </title><link>http://www.blogjava.net/czihong/articles/382136.html</link><dc:creator>Chan Chen</dc:creator><author>Chan Chen</author><pubDate>Tue, 03 Jul 2012 22:17:00 GMT</pubDate><guid>http://www.blogjava.net/czihong/articles/382136.html</guid><wfw:comment>http://www.blogjava.net/czihong/comments/382136.html</wfw:comment><comments>http://www.blogjava.net/czihong/articles/382136.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/czihong/comments/commentRss/382136.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/czihong/services/trackbacks/382136.html</trackback:ping><description><![CDATA[<div><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; ">class</span>&nbsp;BinaryFileBuffer&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;BUFFERSIZE&nbsp;=&nbsp;2048;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;BufferedReader&nbsp;fbr;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;File&nbsp;originalfile;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;String&nbsp;cache;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;empty;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;BinaryFileBuffer(File&nbsp;f,&nbsp;Charset&nbsp;cs)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;IOException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;originalfile&nbsp;=&nbsp;f;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fbr&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;BufferedReader(<span style="color: #0000FF; ">new</span>&nbsp;InputStreamReader(<span style="color: #0000FF; ">new</span>&nbsp;FileInputStream(f),&nbsp;cs),&nbsp;BUFFERSIZE);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reload();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;empty()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;empty;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;reload()&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;IOException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;((<span style="color: #0000FF; ">this</span>.cache&nbsp;=&nbsp;fbr.readLine())&nbsp;==&nbsp;<span style="color: #0000FF; ">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;empty&nbsp;=&nbsp;<span style="color: #0000FF; ">true</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br />&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;empty&nbsp;=&nbsp;<span style="color: #0000FF; ">false</span>;<br />&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; ">catch</span>&nbsp;(EOFException&nbsp;oef)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;empty&nbsp;=&nbsp;<span style="color: #0000FF; ">true</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache&nbsp;=&nbsp;<span style="color: #0000FF; ">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;close()&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;IOException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fbr.close();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;peek()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(empty())<br />&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;cache.toString();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;pop()&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;IOException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;answer&nbsp;=&nbsp;peek();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reload();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;answer;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />}</div></div><img src ="http://www.blogjava.net/czihong/aggbug/382136.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/czihong/" target="_blank">Chan Chen</a> 2012-07-04 06:17 <a href="http://www.blogjava.net/czihong/articles/382136.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>External Sorting</title><link>http://www.blogjava.net/czihong/articles/382135.html</link><dc:creator>Chan Chen</dc:creator><author>Chan Chen</author><pubDate>Tue, 03 Jul 2012 18:27:00 GMT</pubDate><guid>http://www.blogjava.net/czihong/articles/382135.html</guid><wfw:comment>http://www.blogjava.net/czihong/comments/382135.html</wfw:comment><comments>http://www.blogjava.net/czihong/articles/382135.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/czihong/comments/commentRss/382135.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/czihong/services/trackbacks/382135.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Imagine you have the numbers 1 - 99  7  2  6  3  4  8  5  1 And let's suppose that only 3 fit in memory at a time.So you'd break them into chunks of 3 and sort each, storing each result in a separate ...&nbsp;&nbsp;<a href='http://www.blogjava.net/czihong/articles/382135.html'>阅读全文</a><img src ="http://www.blogjava.net/czihong/aggbug/382135.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/czihong/" target="_blank">Chan Chen</a> 2012-07-04 02:27 <a href="http://www.blogjava.net/czihong/articles/382135.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>