<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mr./Ms. Days (MMDays) - 網路, 資訊, 觀察, 生活MMDays &#8211; Algorithm</title>
	<atom:link href="http://mmdays.com/tag/algorithm/feed/" rel="self" type="application/rss+xml" />
	<link>http://mmdays.com</link>
	<description>網路, 產業, 資訊, 觀察, 生活, 電影, 技術, 新知, 科技, 媒體, 趨勢, Web 2.0</description>
	<lastBuildDate>Wed, 08 Feb 2012 17:35:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>搜尋引擎再進化，重新組織搜尋結果</title>
		<link>http://mmdays.com/2008/05/19/search-result-clustering/</link>
		<comments>http://mmdays.com/2008/05/19/search-result-clustering/#comments</comments>
		<pubDate>Mon, 19 May 2008 08:20:57 +0000</pubDate>
		<dc:creator>Mr. Wednesday</dc:creator>
				<category><![CDATA[Mr. Wednesday]]></category>
		<category><![CDATA[Research]]></category>
		<category><![CDATA[Web 2.0]]></category>
		<category><![CDATA[專欄]]></category>
		<category><![CDATA[程式設計]]></category>
		<category><![CDATA[資訊視覺化]]></category>
		<category><![CDATA[關於網路產業]]></category>
		<category><![CDATA[電腦科學]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[classification]]></category>
		<category><![CDATA[clustering]]></category>
		<category><![CDATA[Search Engine]]></category>
		<category><![CDATA[分群]]></category>
		<category><![CDATA[分類]]></category>
		<category><![CDATA[搜尋結果]]></category>
		<category><![CDATA[資訊檢索]]></category>

		<guid isPermaLink="false">http://mmdays.com/?p=5904</guid>
		<description><![CDATA[以目前全球資訊網上擁有的巨量資訊，如果沒有高效率搜尋引擎的幫助，尋找資訊將如同大海撈針一般困難，今天已有許多商業的搜尋引擎試圖滿足此類搜尋工作的需求，例如：Google，Yahoo，Ask與Microsoft Live Search等。搜尋引擎多會依照某種方式進行排序，把相關的網路搜尋結果以排名順序列表一一提供使用者去瀏覽，讓使用者依照搜尋結果摘要的內容自行挑選。然而這樣的瀏覽方式極度沒有效率，因為網路搜尋結果通常相當的多，而一般使用者多只會有耐心瀏覽前若干筆的搜尋結果，而且這類排名順序列表的呈現方式會使得很多關於使用者查詢的子議題通通混雜在一起，很容易造成使用者錯過重要資訊。]]></description>
			<content:encoded><![CDATA[<p><strong>Posted By <a href="http://mmdays.com/category/mr-wednesday"><span style="color: #ff9900;">Mr. Wednesday</span></a></strong></p>
<p>本文同步刊載於《<a title="pcuser" href="http://totalpost.pcuser.com.tw/2AT514.htm" target="_blank">密計偷偷報 No.39</a>》</p>
<p>使用搜尋引擎查詢資料已經是許多人每天不可缺少的必備動作，但是，不知道各位讀者在使用搜尋引擎時是否曾經預想過，你所下的關鍵字會得到怎樣的搜尋結果？在最佳的情況下，搜尋引擎可以馬上回傳你『想要』的搜尋結果。但是更常發生的情況是，電腦跟人腦想得不一樣（人腦：其實你不懂我的心），搜尋結果不是期待中想要的結果，而必須再經過一次次反覆的修改搜尋關鍵字後，才會慢慢貼近心中想要的那個結果。</p>
<h3>全球資訊網上的巨量資訊</h3>
<p>以目前全球資訊網上擁有的巨量資訊，如果沒有高效率搜尋引擎的幫助，尋找資訊將如同大海撈針一般困難，今天已有許多商業的搜尋引擎試圖滿足此類搜尋工作的需求，例如：<a title="google" href="http://www.google.com" target="_blank">Google</a>，<a title="yahoo" href="http://www.yahoo.com/" target="_blank">Yahoo</a>，<a title="ask" href="http://www.ask.com" target="_blank">Ask</a>與<a title="microsoft live search" href="http://www.live.com/" target="_blank">Microsoft Live Search</a>:等。搜尋引擎多會依照某種方式進行排序，把相關的網路搜尋結果以排名順序列表一一提供使用者去瀏覽，讓使用者依照搜尋結果摘要的內容自行挑選。然而這樣的瀏覽方式極度沒有效率，因為網路搜尋結果通常相當的多，而一般使用者多只會有耐心瀏覽前若干筆的搜尋結果，而且這類排名順序列表的呈現方式會使得很多關於使用者查詢的子議題通通混雜在一起，很容易造成使用者錯過重要資訊。</p>
<p><span id="more-5904"></span></p>
<h3>以分類目錄組織全球資訊網</h3>
<p>排名順序列表對於瀏覽性的工作相當有效，譬如說尋找某個組織或機構的首頁，但是對於其他性質的工作，排名順序列表這類的形式並不是最佳的呈現方式。現有常見的改善瀏覽網路搜尋結果方式多是建立一個階層式的分類架構，例如Yahoo或是<a title="dmoz" href="http://www.dmoz.org/" target="_blank">ODP</a> (Open Directory Project)的分類目錄，用階層式分類架構以組織網路搜尋結果，將網路搜尋結果指派進相關的主題之下。然而，這樣的作法也有其缺點，就是這類的分類架構必須依靠人力建立，而依靠人力的缺點就是無法應付整個全球資訊網的量，涵蓋率不夠高。以ODP為例，其涵蓋率不到整個全球資訊網的5%，因此對於某些特定的查詢無法提供良好的搜尋結果組織。</p>
<h3>試圖重新組織搜尋結果</h3>
<p>在搜尋引擎剛起步的年代，搜尋效率與準確度是大家最關注的焦點，Google在搜尋效率與準確度上表現極為優異，也奠定了日後成為搜尋引擎霸主的基礎。但是，事情到此就結束了嗎？不，當然沒有，搜尋技術絕對沒有到此就停滯不前。全球資訊網是一個極度龐大而且非結構性的資訊來源，以關鍵字為基礎的搜尋引擎在回應使用者查詢時都會回傳數以萬計甚至百萬計的結果，而且以一長串列表呈現，對於使用者的應用上經常造成不便。在這個輕易就能利用搜尋工具獲取大量資訊的時代，減少搜尋結果的量並以一個簡潔易懂的方式呈現所有關於查詢的概念無疑是一項重要的工程。</p>
<p><strong>搜尋引擎可以幫使用者輕易地在全球資訊網上找到大量的相關文件，但是過多而且不相關的資訊對使者來說反而會造成困擾。</strong>越來越多的研究都開始注意到要如何根據網路搜尋結果的內容而將其重新組織，如果能有一種更簡潔更清晰易懂的方式來重新組織搜尋結果，必定可以大幅提昇搜尋結果的應用功效。</p>
<h3>文件分類與分群技術</h3>
<p>一個最直覺的想法，如果可以根據搜尋結果的主題來加以分群，就可以一目了然知道搜尋結果包含哪幾類主題。在資訊檢索領域中，文件分類與分群技術已經研究多年，剛好適合應用來解決這個問題。</p>
<p>分類技術配合事先定義好的類別可以幫助將搜尋結果分類到事先定義好的類別內，唯其缺點在於需要事先定義好各類別，而人工定義好的類別對於全球資訊網上快速產生而且變動劇烈的資訊來說，無法快速產生適合的類別來處理。分群技術與分類技術最大的差別在於不需要事先定義好的類別，更適合運用在全球資訊網上處理各式各樣的搜尋結果。</p>
<p>分群技術的演算法眾多，依處理過程主要分成兩大類，一個是由上而下的分割式分群演算法：在起始狀態裡僅只有一個群，每次尋找一個群加以分割，直到該群僅含有一個元素或是群的總數達到臨界值為止。另一個是由下而上的凝聚式分群演算法：在起始狀態裡，每一個群僅含有單一元素，每一回合尋找兩個最相近的群加以合併，直到任兩個群的距離都大於事先定義的臨界值為止。</p>
<p><a href="http://mmdays.com/wp-content/uploads/2008/05/clustering-algorithm.png"><img class="aligncenter size-full wp-image-5905" title="clustering-algorithm" src="http://mmdays.com/wp-content/uploads/2008/05/clustering-algorithm.png" alt="" width="500" height="231" /></a></p>
<h3>目前網路上的自動分群搜尋引擎</h3>
<p>目前網路上已經存在有多個針對搜尋結果重新整理的搜尋引擎（以下畫面皆以搜尋關鍵字apple為例）：</p>
<p><a title="ask" href="http://www.ask.com/" target="_blank">Ask</a></p>
<p><a href="http://mmdays.com/wp-content/uploads/2008/05/ask.jpg"><img class="aligncenter size-full wp-image-5906" title="ask" src="http://mmdays.com/wp-content/uploads/2008/05/ask.jpg" alt="" width="500" height="320" /></a></p>
<p><a title="lexxe" href="http://www.lexxe.com/" target="_blank">Lexxe</a></p>
<p><a href="http://mmdays.com/wp-content/uploads/2008/05/lexx.jpg"><img class="aligncenter size-full wp-image-5907" title="lexx" src="http://mmdays.com/wp-content/uploads/2008/05/lexx.jpg" alt="" width="500" height="320" /></a></p>
<p><a title="vivisimo" href="http://www.vivisimo.com/" target="_blank">Vivisomo</a> / <a title="clusty" href="http://clusty.com/" target="_blank">Clusty</a></p>
<p><a href="http://mmdays.com/wp-content/uploads/2008/05/vivisimo.jpg"><img class="aligncenter size-full wp-image-5908" title="vivisimo" src="http://mmdays.com/wp-content/uploads/2008/05/vivisimo.jpg" alt="" width="500" height="316" /></a></p>
<p><a href="http://mmdays.com/wp-content/uploads/2008/05/clusty.jpg"><img class="aligncenter size-full wp-image-5909" title="clusty" src="http://mmdays.com/wp-content/uploads/2008/05/clusty.jpg" alt="" width="500" height="316" /></a></p>
<p>畫面看起來是不是都有點類似，這幾個搜尋引擎都採用極為相同的呈現方式，在搜尋結果畫面中右側採用條列的方式呈現搜尋結果（與目前的搜尋引擎相同），左邊多了一些根據這次搜尋結果所產生的主題群。主題群以階層式的方式組織，顯示與目前搜尋關鍵字相關的主題。原本可能是幾十頁的搜尋結果現在全部整理成數個重要的主題，可以快速綜觀全局，也不用擔心重要的訊息會被淹沒在茫茫資訊海中。主題群的設計還可以幫助使用者持續修正查詢的關鍵字，更快速準確地找到需要的資訊。</p>
<p>更進一步，搜尋引擎除了自動將搜尋結果自動分群外，還可以以視覺化的方式呈現搜尋結果。</p>
<p><a title="mooter" href="http://www.mooter.com/moot" target="_blank">Mooter</a></p>
<p><a href="http://mmdays.com/wp-content/uploads/2008/05/mooter.jpg"><img class="aligncenter size-full wp-image-5910" title="mooter" src="http://mmdays.com/wp-content/uploads/2008/05/mooter.jpg" alt="" width="500" height="316" /></a></p>
<p><a title="grokker" href="http://www.grokker.com/" target="_blank">Grokker</a></p>
<p><a href="http://mmdays.com/wp-content/uploads/2008/05/groker.jpg"><img class="aligncenter size-full wp-image-5911" title="groker" src="http://mmdays.com/wp-content/uploads/2008/05/groker.jpg" alt="" width="500" height="316" /></a></p>
<h4>優點</h4>
<p>以Grokker為例，從搜尋結果可以發現到視覺化的呈現有許多好處，第一，不同顏色代表不同主題，較大的圈圈表示該主題涵蓋較多的網頁，非常容易辨識。第二，要緊縮還是放鬆查詢結果可以靠進入或是退出代表查詢結果的圈圈。<strong>視覺化呈現的優點就是可以一目了然了解所有相關主題間的相對關係</strong>，不用一頁一頁往下翻尋找搜尋結果，操作便利，而且感覺搜尋結果活潑了起來，讓搜尋變得有趣，不只是死板板的條列式呈現而已。</p>
<h4>缺點</h4>
<p>看了這些例子，眼尖的讀者一定也有發現，這些自動整理出來的主題群，標題下的並不直覺也不易懂，而且各主題間也偶有發生區分得不是很清楚的情況，主題範圍的重疊性與從屬性不一定能準確判斷。而且在實際操作使用的時候，因為要將搜尋結果再組織，必須花費更多計算資源去處理，回傳的時間有點慢，搜尋效率上仍遠遜於傳統的搜尋引擎。</p>
<h3>結論</h3>
<p>搜尋結果分群與視覺化呈現可以快速幫助使用者從看似雜亂的搜尋結果中理出一個頭緒，使得搜尋這件事不單單只是尋找資料而已。<strong>藉由良好的網路搜尋結果自動組織技術，基本應用上將可使網路搜尋結果的利用更加準確與快速，幫助使用者快速瞭解整個搜尋結果的全貌。此外，將有助於網路知識分類樹自動建立，更輕易地利用整個全球資訊網上蘊含的豐富知識。</strong>重新組織搜尋結果是個有潛力的方向，但是如何改善搜尋結果的呈現與執行效率將會是實用與否的重要因素。自動分群搜尋引擎前景將會如何尚有待關注，但的確已走出了一條與傳統搜尋引擎不同的路。<br/>
<div>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td><a href="http://plurktop.mmdays.com/replurkdetail/?link=9bb8e472516b67cbf4e8970a921a6ef5" title="看看其他人討論內容" target="_blank"><img src="http://plurktop.mmdays.com/images/replurk_1.png" style="border:0"></a></td>
</tr>
<tr>
<td><a href="http://plurk.com/?qulaifier=shares&#038;status=http%3A%2F%2Fmmdays.com%2F2008%2F05%2F19%2Fsearch-result-clustering%2F+%28%E6%90%9C%E5%B0%8B%E5%BC%95%E6%93%8E%E5%86%8D%E9%80%B2%E5%8C%96%EF%BC%8C%E9%87%8D%E6%96%B0%E7%B5%84%E7%B9%94%E6%90%9C%E5%B0%8B%E7%B5%90%E6%9E%9C%29+-+%E8%BD%89%E5%99%97%E6%8E%92%E8%A1%8C%E6%A6%9C+http%3A%2F%2Fplurktop.mmdays.com%2Freplurk" title="推到噗浪" target="_blank"><img style="border:0" src="http://plurktop.mmdays.com/images/replurk_2.png" /></a></td>
</tr>
</table>
</div>
<p><br/><a href="http://www.facebook.com/MMDays" target="_blank">加入MMDays在facebook的粉絲團 隨時閱讀最新文章</a><br/></p>
]]></content:encoded>
			<wfw:commentRss>http://mmdays.com/2008/05/19/search-result-clustering/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Stack堆疊的資料結構</title>
		<link>http://mmdays.com/2008/04/03/stack/</link>
		<comments>http://mmdays.com/2008/04/03/stack/#comments</comments>
		<pubDate>Wed, 02 Apr 2008 17:41:17 +0000</pubDate>
		<dc:creator>Mr. Thursday</dc:creator>
				<category><![CDATA[Mr. Thursday]]></category>
		<category><![CDATA[專欄]]></category>
		<category><![CDATA[電腦科學]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[data structure]]></category>
		<category><![CDATA[post-order]]></category>
		<category><![CDATA[stack]]></category>
		<category><![CDATA[tree]]></category>
		<category><![CDATA[堆疊]]></category>
		<category><![CDATA[後序]]></category>
		<category><![CDATA[樹]]></category>
		<category><![CDATA[演算法]]></category>
		<category><![CDATA[資料結構]]></category>

		<guid isPermaLink="false">http://mmdays.com/2008/04/03/stack/</guid>
		<description><![CDATA[Posted By Mr. Thursday 不知道各位是否有接聽電話插撥 (call waiting) 的經驗？ 我們會先把第一個接聽的人先暫時停著，然後接聽新打來的電話。不知道目前插撥最多能接聽多少通電話？假設依照這個方法一直接聽新的插撥電話，就會一直把上一通電話暫時儲存，等新接通的電話結束後，再回復上一通、上上一通、一直到第一通接聽的電話。 堆疊 (Stack) 就是類似的資料結構。「堆疊」有兩個方法 (method) 可以呼叫：推進 (push) 和 彈出 (pop)。透過這兩個方法的使用，我們可以達到讓資料「先進後出」的效果 (LIFO: Last In First Out)。甚麼是先進後出呢？讓我們再舉一個例子：搭電梯。當我們搭電梯的時候，通常最先進電梯的會擠在後面，後進電梯的比較靠近門口。如果都是同一層離開電梯，剛才比較慢近來電梯的人，反而是比較早離開電梯的人，這就是「先進後出」(LIFO) 的效果了。 再回到剛才接聽插撥電話的例子，正好就是先進後出的例子！最後插撥的先結束對話，最早打來的最慢結束對話。接下來讓我們看看，堆疊實際運作的情形，會向下面這一張動畫所顯示的：   上面這張圖就是顯示堆疊 (stack) 把三個數字 1、2、3分別push到堆疊裡面的過程。堆疊本身看起來就像是我們把書本放在桌上的樣子一般，最早放的書本會在最底下，最後放的書本會在最上面。當我們把書本從最上面開始拿 (pop) 的時候，會拿到最後放的書本，最後才拿到一開始放下去的書本。因此把數字從堆疊 (stack) 裡面 pop出來的過程，會像下面這張動畫顯示的樣子： 從上面這張圖，我們可以看出來，我們依照1、2、3的順序把數字 push 到堆疊裡面，pop的時候出來的順序就會變成 3、2、1，也就是先進後出了！ 堆疊在遞迴式走訪樹的應用 介紹完了堆疊，最常應用到堆疊這個資料結構的演算法，應該就是「遞迴」 (recursive) 方法了。所謂遞迴，就像是站在兩面鏡子之間，相同的影像不停地反射，只是每反射一次都小一些。之前接聽插撥的例子也是遞迴的例子，就是先暫停目前的工作，但是不是忘記，而是先依照順序存起來，然後先處理新的工作。等到新的工作處理完，再按照先進後出的順序，把剛才暫停的工作回覆過來處理好。   因此，之前在〈由樹的前序、中序、後序走法來談資料結構〉裡面提到的前序、中序、後序的走法，也可以透過遞迴加上堆疊的資料結構來完成！譬如說上面這棵樹，我們從樹根7開始，發現有分支就往下走，但是我們先不把樹根忘掉，因此把樹根7 push到堆疊裡面。接者按照同樣的方法，往樹葉的方向走，一直走到樹葉的部分 ，再按照先進後出的順序，把堆疊pop出來的東西印出來，就是後序走訪這棵樹的方式了！ 遞迴走訪樹的演算法如下 (移到文章後面以方便整理版面) 讓我們跑跑上面這一段演算法，演算法可以運作的東西，就是堆疊(stack)這個資料結構，以及輸入的這棵樹的資料結構。最後會輸出後序走訪這棵樹的過程。(請參考文章後面的過程，這邊先略過整理一下版面) 演算法和資料結構的用途  因此到目前為止，我們終於知道了演算法和資料結構的初步的概念，也終於看到了一些基本的應用，像是「樹」、「堆疊」、「遞迴」等應用。然而或許還是會有些疑惑，就是演算法和資料結構，要怎樣子在電腦上面跑呢？如果說電腦聽不懂人類的自然語言，電腦又要怎樣子聽懂演算法的敘述呢？這邊我想先用一個比方來說明，也就是作文的比方。 當我們寫一篇作文的時候，我們可能會有一些寫作方法，譬如說第一段寫主旨，第二段寫例子，第三段寫反立推翻第一個例子，第四段寫結論，如此起承轉合，完成一篇文章。我們可能進一步把題目分成敘述文、論說文、和抒情文。不同種類的文章，我們會有不同的段落起承轉合。然而各類題目的段落安排方式，和我們用字淺詞的方式，可以分開來。甚至同樣的段落安排，我們可以用英文來寫。 因此演算法和電腦的關係，有些類似上面寫作比方的關係。電腦只看得懂機器0101碼，但是我們有高階程式語言，像是C, C++, 或是JAVA，透過編譯器 (compiler) [...]]]></description>
			<content:encoded><![CDATA[<p align="left"><strong>Posted By <font color="#008000">Mr. Thursday</font></strong></p>
<p>不知道各位是否有接聽電話插撥 (call waiting) 的經驗？ 我們會先把第一個接聽的人先暫時停著，然後接聽新打來的電話。不知道目前插撥最多能接聽多少通電話？假設依照這個方法一直接聽新的插撥電話，就會一直把上一通電話暫時儲存，等新接通的電話結束後，再回復上一通、上上一通、一直到第一通接聽的電話。</p>
<p><strong>堆疊</strong> (<strong>Stack</strong>) 就是類似的資料結構。「堆疊」有兩個方法 (method) 可以呼叫：推進 (<strong>push</strong>) 和 彈出 (<strong>pop</strong>)。透過這兩個方法的使用，我們可以達到讓資料「<strong>先進後出</strong>」的效果 (LIFO: Last In First Out)。甚麼是<strong>先進後出</strong>呢？讓我們再舉一個例子：<strong>搭電梯</strong>。當我們搭電梯的時候，通常最先進電梯的會擠在後面，後進電梯的比較靠近門口。如果都是同一層離開電梯，剛才比較慢近來電梯的人，反而是比較早離開電梯的人，這就是「先進後出」(<strong>LIFO</strong>) 的效果了。</p>
<p>再回到剛才接聽插撥電話的例子，正好就是先進後出的例子！最後插撥的先結束對話，最早打來的最慢結束對話。接下來讓我們看看，堆疊實際運作的情形，會向下面這一張動畫所顯示的：</p>
<p align="center"> <img src="http://mmdays.com/wp-content/uploads/2008/04/push.gif" alt="push" /></p>
<p><span id="more-5772"></span>上面這張圖就是顯示<strong>堆疊</strong> (stack) 把三個數字 1、2、3分別push到堆疊裡面的過程。堆疊本身看起來就像是我們把書本放在桌上的樣子一般，最早放的書本會在最底下，最後放的書本會在最上面。當我們把書本從最上面開始拿 (pop) 的時候，會拿到最後放的書本，最後才拿到一開始放下去的書本。因此把數字從堆疊 (stack) 裡面 pop出來的過程，會像下面這張動畫顯示的樣子：</p>
<p align="center"><img src="http://mmdays.com/wp-content/uploads/2008/04/pop.gif" alt="pop" /></p>
<p>從上面這張圖，我們可以看出來，我們依照1、2、3的順序把數字 push 到堆疊裡面，pop的時候出來的順序就會變成 3、2、1，也就是先進後出了！</p>
<p align="center"><strong>堆疊在遞迴式走訪樹的應用</strong></p>
<p>介紹完了<strong>堆疊</strong>，最常應用到堆疊這個資料結構的演算法，應該就是「<strong>遞迴</strong>」 (recursive) 方法了。所謂<strong>遞迴</strong>，就像是站在兩面鏡子之間，相同的影像不停地反射，只是每反射一次都小一些。之前接聽插撥的例子也是<strong>遞迴</strong>的例子，就是<strong>先暫停目前的工作，但是不是忘記，而是先依照順序存起來，然後先處理新的工作。等到新的工作處理完，再按照先進後出的順序，把剛才暫停的工作回覆過來處理好</strong>。</p>
<p align="center"> <img src="http://mmdays.com/wp-content/uploads/2008/04/post.jpg" alt="post" /></p>
<p>因此，之前在〈<a href="http://mmdays.com/2008/01/19/data_structure_tree/">由樹的前序、中序、後序走法來談資料結構</a>〉裡面提到的前序、中序、後序的走法，也可以透過<strong>遞迴</strong>加上<strong>堆疊</strong>的資料結構來完成！譬如說上面這棵樹，我們從樹根7開始，發現有分支就往下走，但是我們先不把樹根忘掉，因此把樹根7 push到堆疊裡面。接者按照同樣的方法，往樹葉的方向走，一直走到樹葉的部分 ，再按照先進後出的順序，把堆疊pop出來的東西印出來，就是後序走訪這棵樹的方式了！</p>
<p>遞迴走訪樹的演算法如下 (<em>移到文章後面以方便整理版面</em>)</p>
<p>讓我們跑跑上面這一段演算法，演算法可以運作的東西，就是<strong>堆疊</strong>(stack)這個資料結構，以及輸入的這棵<strong>樹</strong>的資料結構。最後會輸出<strong>後序走訪這棵樹</strong>的過程。(<em>請參考文章後面的過程，這邊先略過整理一下版面</em>)</p>
<p align="center"><strong>演算法和資料結構的用途</strong> </p>
<p>因此到目前為止，我們終於知道了演算法和資料結構的初步的概念，也終於看到了一些基本的應用，像是「樹」、「堆疊」、「遞迴」等應用。然而或許還是會有些疑惑，就是演算法和資料結構，要怎樣子在電腦上面跑呢？如果說電腦聽不懂人類的自然語言，電腦又要怎樣子聽懂演算法的敘述呢？這邊我想先用一個比方來說明，也就是作文的比方。</p>
<p>當我們寫一篇作文的時候，我們可能會有一些<strong>寫作方法</strong>，譬如說第一段寫主旨，第二段寫例子，第三段寫反立推翻第一個例子，第四段寫結論，如此起承轉合，完成一篇文章。我們可能進一步把題目分成敘述文、論說文、和抒情文。不同種類的文章，我們會有不同的段落起承轉合。然而各類題目的段落安排方式，和我們用字淺詞的方式，可以分開來。甚至同樣的段落安排，我們可以用英文來寫。</p>
<p>因此演算法和電腦的關係，有些類似上面寫作比方的關係。電腦只看得懂機器0101碼，但是我們有高階程式語言，像是C, C++, 或是JAVA，透過編譯器 (compiler) 或是直譯器 (Interpreter)，可以把我們寫的程式翻譯成機器看的懂的機器0101碼。程式語言，就如同寫作的時候，可能用中文寫，也可能用英文寫。但是演算法和資料結構，則是像寫作的時後段落安排的方法，論說文一種方法，敘述文一種方法，抒情文一種方法，是一種<strong>介於作文題目和文章句子之間的轉換過程</strong>！</p>
<p>整理起來，寫作可以分成下面四個層次：</p>
<ol>
<li>作文題目和題型 (敘述文、論說文、抒情文、其他題型)</li>
<li>段落安排 (針對題型的解決方法)</li>
<li>文章實際的句子 (可以是中文、也可以是英文)</li>
<li>每個單字的字母筆劃，或是中文字的筆劃 (包括標點符號的使用)</li>
</ol>
<p>演算法資料結構對應這個層次的比方：</p>
<ol>
<li>要電腦處理的問題和問題類型 (排序、搜尋、比對)</li>
<li>演算法和資料結構 (針對問題提出的解決方法)</li>
<li>實際寫出程式 (演算法可以和程式一一對應，但不限任一種程式語言)</li>
<li>程式透過編譯器(compiler)翻譯成機器0101碼</li>
</ol>
<p>不知道看完這個例子，各位是否更了解資料結構的角色呢？電腦看不懂演算法或資料結構，但是演算法和資料結構，卻是<strong>問題解法和程式語言之間的橋樑</strong>！</p>
<p>下面列出剛才提到的地迴走訪樹的演算法和執行過程。<strong>樹</strong> (tree) 除了可以排序、搜尋、搭配遞迴和堆疊以外，還有<strong>本體論</strong> (Ontology) 的應用。其他各種樹狀結構，像是<strong>壘堆</strong> (heap)、追求效率而發明的<strong>紅黑樹</strong> (<a href="http://www.ececs.uc.edu/~franco/C321/html/RedBlack/redblack.html">Red-Black Tree</a>) 和<strong>費布那西樹</strong> (<a href="http://demonstrations.wolfram.com/FibonacciTree/">Fibonacci Tree</a>)等等。日後有機會再一一向各位介紹吧！</p>
<p align="center"><strong>遞迴走訪樹的演算法如下</strong></p>
<p>1. 設定目前節點在樹根</p>
<p>2. 如果目前節點有子節點 (child node)，就把目前節點先 push到堆疊，然後往下走。有兩個子節點的話先走左邊再走右邊的子節點。</p>
<p>3. 如果目前節點沒有子節點 (child node)，或是子節點已經拜訪過，就印出目前節點的號碼，並且 pop 出堆疊上一次儲存的節點，設定成現在要拜訪的節點，然後回到步驟2，直到堆疊變成空堆疊為止。</p>
<p align="center"><strong>執行遞迴和堆疊來後序拜訪一棵樹的執行過程</strong></p>
<p><strong>step1: </strong></p>
<p>current node: 7</p>
<p>stack: (empty)</p>
<p>printed order: (empty)</p>
<p><strong>step2:</strong></p>
<p>current node: 7</p>
<p>stack: 7   (###push 7###)</p>
<p>printed order: (empty)</p>
<p><strong>step3:</strong></p>
<p>current node: 3  (###go to left child node###)</p>
<p>stack: 7</p>
<p>printed order: (empty)</p>
<p><strong>step4:</strong></p>
<p>current node: 3</p>
<p>stack: 7, 3  (###push 3###)</p>
<p>printed order: (empty)</p>
<p><strong>step5:</strong></p>
<p>current node: 1  (###go to left child node###)</p>
<p>stack: 7, 3 </p>
<p>printed order: (empty)</p>
<p><strong>step6:</strong></p>
<p>current node: 1</p>
<p>stack: 7, 3</p>
<p>printed order: 1 (###print 1 because no other child nodes###)</p>
<p><strong> step7:</strong></p>
<p>current node: 3  (###go back to node 3###)</p>
<p>stack: 7  (###pop 3###)</p>
<p>printed order: 1</p>
<p><strong>step8:</strong></p>
<p>current node: 2  (###go to right child node)</p>
<p>stack: 7, 3  (###push 3 again###)</p>
<p>printed order: 1</p>
<p><strong>step9:</strong></p>
<p>current node: 2</p>
<p>stack: 7, 3</p>
<p>printed order: 1, 2 (###print 2 because no other child nodes###)</p>
<p><strong>step10:</strong></p>
<p>current node: 3  (###go back to node 3###)</p>
<p>stack: 7  (###pop 3###)</p>
<p>printed order: 1, 2</p>
<p><strong>step11:</strong></p>
<p>current node: 3 </p>
<p>stack: 7 </p>
<p>printed order: 1, 2, 3 (###print 3 because child nodes are visited###)</p>
<p><strong>step12:</strong></p>
<p>current node: 7 (###go back to node 7###)</p>
<p>stack: (empty) (###pop 7###)</p>
<p>printed order: 1, 2, 3</p>
<p><strong>step13:</strong></p>
<p>current node: 6 (###go to right child node###)</p>
<p>stack: 7 (###push back 7###)</p>
<p>printed order: 1, 2, 3</p>
<p><strong>step14:</strong></p>
<p>current node: 6</p>
<p>stack: 7, 6  (###push 6###)</p>
<p>printed order: 1, 2, 3</p>
<p><strong>step15:</strong></p>
<p>current node: 4  (###go to left child node###)</p>
<p>stack: 7, 6 </p>
<p>printed order: 1, 2, 3</p>
<p><strong>step16:</strong></p>
<p>current node: 4</p>
<p>stack: 7, 6</p>
<p>printed order: 1, 2, 3, 4 (###print 4 because no other child nodes###)</p>
<p><strong> step17:</strong></p>
<p>current node: 6  (###go back to node 6###)</p>
<p>stack: 7  (###pop 6###)</p>
<p>printed order: 1, 2, 3, 4</p>
<p><strong>step18:</strong></p>
<p>current node: 5  (###go to right child node)</p>
<p>stack: 7, 6  (###push 6 again###)</p>
<p>printed order: 1, 2, 3, 4</p>
<p><strong>step19:</strong></p>
<p>current node: 5</p>
<p>stack: 7, 6</p>
<p>printed order: 1, 2, 3, 4, 5 (###print 5 because no other child nodes###)</p>
<p><strong>step20:</strong></p>
<p>current node: 6  (###go back to node 6###)</p>
<p>stack: 7  (###pop 6###)</p>
<p>printed order: 1, 2, 3, 4, 5</p>
<p><strong>step21:</strong></p>
<p>current node: 6 </p>
<p>stack: 7 </p>
<p>printed order: 1, 2, 3, 4, 5, 6 (###print 6 because child nodes are visited###)</p>
<p><strong>step22:</strong></p>
<p>current node: 7 (###go back to node 7###)</p>
<p>stack: (empty) (###pop 7###)</p>
<p>printed order: 1, 2, 3, 4, 5, 6</p>
<p><strong>step23:</strong></p>
<p>current node: 7</p>
<p>stack: (empty)</p>
<p>printed order: 1, 2, 3, 4, 5, 6, 7 (###print 7 because child nodes are visited###)</p>
<p>done!<br/>
<div>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td><a href="http://plurktop.mmdays.com/replurkdetail/?link=fa708c3d8c5370e48f31446ee8977b0a" title="看看其他人討論內容" target="_blank"><img src="http://plurktop.mmdays.com/images/replurk_1.png" style="border:0"></a></td>
</tr>
<tr>
<td><a href="http://plurk.com/?qulaifier=shares&#038;status=http%3A%2F%2Fmmdays.com%2F2008%2F04%2F03%2Fstack%2F+%28Stack%E5%A0%86%E7%96%8A%E7%9A%84%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B%29+-+%E8%BD%89%E5%99%97%E6%8E%92%E8%A1%8C%E6%A6%9C+http%3A%2F%2Fplurktop.mmdays.com%2Freplurk" title="推到噗浪" target="_blank"><img style="border:0" src="http://plurktop.mmdays.com/images/replurk_2.png" /></a></td>
</tr>
</table>
</div>
<p><br/><a href="http://www.facebook.com/MMDays" target="_blank">加入MMDays在facebook的粉絲團 隨時閱讀最新文章</a><br/></p>
]]></content:encoded>
			<wfw:commentRss>http://mmdays.com/2008/04/03/stack/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>二元樹在排序的應用</title>
		<link>http://mmdays.com/2008/03/16/tree_sort/</link>
		<comments>http://mmdays.com/2008/03/16/tree_sort/#comments</comments>
		<pubDate>Sat, 15 Mar 2008 17:05:49 +0000</pubDate>
		<dc:creator>Mr. Thursday</dc:creator>
				<category><![CDATA[Mr. Thursday]]></category>
		<category><![CDATA[專欄]]></category>
		<category><![CDATA[電腦科學]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[binary tree]]></category>
		<category><![CDATA[data structure]]></category>
		<category><![CDATA[sort]]></category>
		<category><![CDATA[sorting]]></category>
		<category><![CDATA[二元樹]]></category>
		<category><![CDATA[排序]]></category>
		<category><![CDATA[演算法]]></category>
		<category><![CDATA[資料結構]]></category>

		<guid isPermaLink="false">http://mmdays.com/2008/03/16/tree_sort/</guid>
		<description><![CDATA[Posted By Mr. Thursday 在〈由樹的前序、中序、後序走法來談資料結構〉文章裡面提到了演算法就像是做事情的方法，資料結構則是對應演算法可以運作的東西，譬如說刮鬍子有步驟一、步驟二、步驟三，但是要有刮鬍刀、插頭、以及鬍鬚，那些步驟才有運作的東西，甚至不同的刮鬍刀，也會讓同樣的步驟有不同的執行效率，或是連原來的步驟都要改變，譬如說不是電動刮鬍刀，原來步驟裡面插插頭的那一步，也就可以不用作了。演算法和資料結構之間的關係也是如此，譬如說排序的演算法，可以用不同的資料結構來實現，好的資料結構，可能某一種排序演算法最適合，對其他種排序演算法，可能反而讓速度變慢。 因此，演算法和資料結構，通常會一起考慮，而演算法每一步，也就是電腦可以實現的基本步驟所組成。譬如說兩個數字相加，或是把「樹」這個資料結構裡面的節點根據某種規則移動，都是電腦運算基本步驟所可以達成的。但是如果步驟是「改善排序的品質」的敘述，電腦可能就看不懂了，這時候就是程式設計師，把這些人看的懂的需求，轉換成電腦可以實現的步驟，也就是演算法和對應的資料結構，最後再用程式 (編程) (program)，變成電腦真的可以執行的語言，達到最初想要執行的功能。那麼今天想要完成的功能是甚麼呢？「排序」，排序就是把原本雜亂無章的一堆東西，按照某種順序排好，譬如說圖書館裡面的書籍，按照書籍的編號有小到大排好，譬如說醫院的病歷，按照病歷號碼有小到大排好，譬如說一堆檔案，按照字母順序或是檔案時間順序有早到晚排好，這些都是排序的應用。那麼電腦要如何完成「排序」(sort) 這件工作呢？「二元樹」 (binary tree) 怎樣子應用在排序這項工作呢？ 在〈由樹的前序、中序、後序走法來談資料結構〉裡面提到了「樹」的資料結構，也提到了樹的三種走法，並且用「二元樹」 (binary tree) 為例子來講解。二元樹就是一種樹，只是每個節點 (node) 都只有兩個子節點 (child node)，看起來就像下面這張圖：   就這樣子，一層一層的樹枝分岔下去，只是每次只有兩個分岔，就變成二元樹 (binary tree) 了。假如子節點還有子節點，變成孫節點 (grand children node)，那麼子節點和孫節點一起，可以稱做一顆子樹 (sub-tree) ，也就是看成有一顆比較小的樹，接在子節點的位置上面，這就是上圖裡面虛線三角形代表的部分了。 介紹了二元樹以後，我們已經有了資料結構。接下來就是演算法的步驟，要怎樣子透過二元樹，完成「排序」的功能。我們先假定要把一組正整數數字按照大小排好就好，假定我們看到了 1,5,3,2,6,7,4 這七個數字。我們每看到一個數字，就進行以下步驟： (1) 從樹的樹根 (root) 開始，和每個節點比較 (2) 如果現在這個數字，比現在這個節點的數字小，往左邊的子樹 (sub-tree) 走，否則就往右走 (3) 重覆步驟(2) ，比較新遇到的節點，和現在輸入的數字。如果已經走到樹的結尾，就停止。 根據這三個步驟，假設已經排好了2,4,5,6,7，然後現在輸入一個新的數字 &#8220;3&#8243;。那麼上面這幾步執行的過程，可以用下面這個動畫表示： 假設3排好以後，我們又遇到了&#8221;1&#8243;，那麼接下來執行剛才演算法步驟的過程，會像下面這張動畫一樣：   不知道各位讀者看完了這兩張動畫，是否有比較了解，二元樹怎樣子搭配剛才的排序演算法，把數字排好呢？不過怎樣子看的出來，這棵樹把數字排好了呢？我們只要用「中序」(mid-order) 的方式，把這棵樹拜訪一遍，就是由小到大的方式把數字排序好的唸法了。 譬如說第二張動畫，如果用中序拜訪這棵樹，就會得到1,2,3,4,5,6,7的結果，也就是說，雖然輸入資料的順序是4,2,6,7,5,3,1，但是透過二元樹，以及上面很簡單、電腦可以執行的三個步驟，我們就把數字由小到大排好了！ 當然，這個演算法只有三步，每次比較數字大小之後，在二元樹上面不是往左就是往右，沒有其他複雜的步驟，但是執行效率就不是最好的了，怎樣子知道一種演算法的效率好不好呢？就等以後介紹其他排序演算法的時候，再一起比較說明吧！另外剛才演算法也省略了，如果兩個數字相等的情況。無論如何，如果只是簡單的排序應用，這個演算法搭配二元樹，應該就足夠了。 其他常見的排序演算法還有哪些呢？包括選擇排序 (selection sort)、插入排序 (insertion [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Posted By <font color="#008000">Mr. Thursday</font></strong></p>
<p>在〈<a href="http://mmdays.com/2008/01/19/data_structure_tree/">由樹的前序、中序、後序走法來談資料結構</a>〉文章裡面提到了<strong>演算法</strong>就像是做事情的方法，<strong>資料結構</strong>則是對應演算法可以運作的東西，譬如說刮鬍子有步驟一、步驟二、步驟三，但是要有刮鬍刀、插頭、以及鬍鬚，那些步驟才有運作的東西，甚至不同的刮鬍刀，也會讓同樣的步驟有不同的執行效率，或是連原來的步驟都要改變，譬如說不是電動刮鬍刀，原來步驟裡面插插頭的那一步，也就可以不用作了。<strong>演算法</strong>和<strong>資料結構</strong>之間的關係也是如此，譬如說排序的演算法，可以用不同的資料結構來實現，好的資料結構，可能某一種排序演算法最適合，對其他種排序演算法，可能反而讓速度變慢。</p>
<p>因此，<strong>演算法</strong>和<strong>資料結構</strong>，通常會一起考慮，而演算法每一步，也就是電腦可以實現的基本步驟所組成。譬如說兩個數字相加，或是把「樹」這個資料結構裡面的節點根據某種規則移動，都是電腦運算基本步驟所可以達成的。但是如果步驟是「改善排序的品質」的敘述，電腦可能就看不懂了，這時候就是程式設計師，把這些人看的懂的需求，轉換成電腦可以實現的步驟，也就是演算法和對應的資料結構，最後再用程式 (編程) (program)，變成電腦真的可以執行的語言，達到最初想要執行的功能。那麼今天想要完成的功能是甚麼呢？「<strong>排序</strong>」，排序就是把原本雜亂無章的一堆東西，按照某種順序排好，譬如說圖書館裡面的書籍，按照<u>書籍的編號</u>有小到大排好，譬如說<u>醫院的病歷</u>，按照病歷號碼有小到大排好，譬如說一堆<u>檔案</u>，按照字母順序或是檔案時間順序有早到晚排好，這些都是排序的應用。那麼電腦要如何完成「<strong>排序</strong>」(sort) 這件工作呢？「<strong>二元樹</strong>」 (binary tree) 怎樣子應用在排序這項工作呢？</p>
<p><span id="more-5709"></span></p>
<p>在〈<a href="http://mmdays.com/2008/01/19/data_structure_tree/">由樹的前序、中序、後序走法來談資料結構</a>〉裡面提到了「<strong>樹</strong>」的資料結構，也提到了樹的三種走法，並且用「<strong>二元樹</strong>」 (binary tree) 為例子來講解。<strong>二元樹</strong>就是一種樹，只是每個<strong>節點</strong> (node) 都只有兩個<strong>子節點</strong> (child node)，看起來就像下面這張圖：</p>
<p align="center"> <img border="0" align="absMiddle" width="400" src="http://mmdays.com/wp-content/uploads/2008/01/mid.jpg" height="250" /></p>
<p>就這樣子，一層一層的樹枝分岔下去，只是每次只有<strong>兩個分岔</strong>，就變成<strong>二元樹</strong> (binary tree) 了。假如子節點還有子節點，變成孫節點 (grand children node)，那麼子節點和孫節點一起，可以稱做一顆<strong>子樹</strong> (sub-tree) ，也就是看成有一顆比較小的樹，接在子節點的位置上面，這就是上圖裡面虛線三角形代表的部分了。</p>
<p>介紹了二元樹以後，我們已經有了資料結構。接下來就是演算法的步驟，要怎樣子透過二元樹，完成「<strong>排序</strong>」的功能。我們先假定要把一組正整數數字按照大小排好就好，假定我們看到了 1,5,3,2,6,7,4 這七個數字。我們每看到一個數字，就進行以下步驟：</p>
<p>(1) 從樹的樹根 (root) 開始，和每個節點比較</p>
<p>(2) 如果現在這個數字，比現在這個節點的數字小，往左邊的子樹 (sub-tree) 走，否則就往右走</p>
<p>(3) 重覆步驟(2) ，比較新遇到的節點，和現在輸入的數字。如果已經走到樹的結尾，就停止。</p>
<p>根據這三個步驟，假設已經排好了2,4,5,6,7，然後現在輸入一個新的數字 &#8220;3&#8243;。那麼上面這幾步執行的過程，可以用下面這個動畫表示：</p>
<p align="center"><img src="http://mmdays.com/wp-content/uploads/2008/03/sort1.gif" alt="sort1" /></p>
<p>假設3排好以後，我們又遇到了&#8221;1&#8243;，那麼接下來執行剛才演算法步驟的過程，會像下面這張動畫一樣：</p>
<p align="center"> <img src="http://mmdays.com/wp-content/uploads/2008/03/sort2.gif" alt="sort2" /></p>
<p>不知道各位讀者看完了這兩張動畫，是否有比較了解，二元樹怎樣子搭配剛才的排序演算法，把數字排好呢？不過怎樣子看的出來，這棵樹把數字排好了呢？我們只要用「<strong>中序</strong>」(mid-order) 的方式，把這棵樹拜訪一遍，就是由小到大的方式把數字排序好的唸法了。</p>
<p>譬如說第二張動畫，如果用中序拜訪這棵樹，就會得到1,2,3,4,5,6,7的結果，也就是說，雖然輸入資料的順序是4,2,6,7,5,3,1，但是透過二元樹，以及上面很簡單、電腦可以執行的三個步驟，我們就把數字由小到大排好了！</p>
<p>當然，這個演算法只有三步，每次比較數字大小之後，在二元樹上面不是往左就是往右，沒有其他複雜的步驟，但是<strong>執行效率</strong>就不是最好的了，怎樣子知道一種演算法的效率好不好呢？就等以後介紹其他排序演算法的時候，再一起比較說明吧！另外剛才演算法也省略了，如果兩個數字相等的情況。無論如何，如果只是簡單的排序應用，這個演算法搭配二元樹，應該就足夠了。</p>
<p>其他常見的排序演算法還有哪些呢？包括<strong>選擇排序</strong> (selection sort)、<strong>插入排序</strong> (insertion sort)、<strong>泡泡排序</strong> (bubble sort)、<strong>快速排序</strong> (quick sort)、<strong>合併排序</strong> (merge sort)、以及正整數才能用的<strong>桶子排序</strong> (bucket sort)，有興趣的讀者不妨先用<a href="http://maven.smith.edu/~thiebaut/java/sort/">這個</a>JAVA Applet動畫模擬器來看看各種排序方法的動畫。最後也找了一段Youtube的排序動畫影片：</p>
<p align="center"><!-- start insertion by YouTube Brackets, robertbuzink.nl --><span class="youtube"><object width="425" height="350" type="application/x-shockwave-flash" data="http://www.youtube.com/v/JdXoUgYQebM"> <param name="movie" value="http://www.youtube.com/v/JdXoUgYQebM" /><param name="wmode" value="transparent" /></object></span><!-- end Youtube Brackets insertion --></p>
<p>最近似乎也是研究所考試的季節，順便祝福各位資訊相關的考生，演算法和資料結構都能越記越熟！</p>
<p>相關連結</p>
<ul>
<li>(Wikipedia) <a href="http://zh.wikipedia.org/wiki/%E4%BA%8C%E5%8F%89%E6%A0%91">二元樹</a>, <a href="http://en.wikipedia.org/wiki/Binary_tree">binary tree</a></li>
<li><a href="http://maven.smith.edu/~thiebaut/java/sort/">排序演算法Java Applet動畫</a></li>
<li><a href="http://www.youtube.com/watch?v=JdXoUgYQebM&amp;fmt=18">排序演算法Youtube影片</a></li>
</ul>
<p>演算法相關文章</p>
<ul>
<li><a href="http://mmdays.com/2008/01/19/data_structure_tree/">由樹的前序、中序、後序走法來談資料結構</a></li>
<li><a href="http://mmdays.com/2007/10/19/tf_idf/">字字珠璣: TF 和 IDF</a></li>
<li><a href="http://mmdays.com/2007/10/05/travelling_salesman/">旅行中的商人與負世界</a></li>
<li><a href="http://mmdays.com/2007/09/28/cpu_scheduling/">排程問題與CPU Scheduling</a></li>
<li><a href="http://mmdays.com/2007/06/29/search_algorithm_prime_number/">從尋找質數談談搜尋演算法</a></li>
<li><a href="http://mmdays.com/2007/06/12/dining_philosopher-2/">千頭萬緒：平行計算和吃飯中的哲學家</a></li>
<li><a href="http://mmdays.com/2007/05/24/recursive/">遞迴之美: 數學, 電腦科學與碎形</a></li>
<li><a href="http://mmdays.com/2007/05/18/knn_errata/">KNN演算法 (更正篇)</a></li>
<li><a href="http://mmdays.com/2007/05/16/knn/">KNN演算法</a></li>
</ul>
<p><br/>
<div>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td><a href="http://plurktop.mmdays.com/replurkdetail/?link=75693b3cc47abbb43a0341b0831223ea" title="看看其他人討論內容" target="_blank"><img src="http://plurktop.mmdays.com/images/replurk_1.png" style="border:0"></a></td>
</tr>
<tr>
<td><a href="http://plurk.com/?qulaifier=shares&#038;status=http%3A%2F%2Fmmdays.com%2F2008%2F03%2F16%2Ftree_sort%2F+%28%E4%BA%8C%E5%85%83%E6%A8%B9%E5%9C%A8%E6%8E%92%E5%BA%8F%E7%9A%84%E6%87%89%E7%94%A8%29+-+%E8%BD%89%E5%99%97%E6%8E%92%E8%A1%8C%E6%A6%9C+http%3A%2F%2Fplurktop.mmdays.com%2Freplurk" title="推到噗浪" target="_blank"><img style="border:0" src="http://plurktop.mmdays.com/images/replurk_2.png" /></a></td>
</tr>
</table>
</div>
<p><br/><a href="http://www.facebook.com/MMDays" target="_blank">加入MMDays在facebook的粉絲團 隨時閱讀最新文章</a><br/></p>
]]></content:encoded>
			<wfw:commentRss>http://mmdays.com/2008/03/16/tree_sort/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>排程問題與CPU Scheduling</title>
		<link>http://mmdays.com/2007/09/28/cpu_scheduling/</link>
		<comments>http://mmdays.com/2007/09/28/cpu_scheduling/#comments</comments>
		<pubDate>Thu, 27 Sep 2007 16:08:18 +0000</pubDate>
		<dc:creator>Mr. Thursday</dc:creator>
				<category><![CDATA[Mr. Thursday]]></category>
		<category><![CDATA[專欄]]></category>
		<category><![CDATA[電腦科學]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[CPU Scheduling]]></category>
		<category><![CDATA[Operating System]]></category>

		<guid isPermaLink="false">http://mmdays.com/2007/09/28/cpu_scheduling/</guid>
		<description><![CDATA[Posted By Mr. Thursday 如果今天有一台機器，N個人要用，每個人使用的時間分別是t1, t2, &#8230;, tn，那麼怎樣子才能讓等待的時間最少呢？如果是以每個人的角度來說的話，當然是先搶先贏啦！不過如果是以這N個人所屬機構的角度來看，要讓全部人的等待時間最少，要如何安排使用機器的順序呢？這個時候作業系統 (OS: Operating System) 裡面的CPU Scheduling方法，就可以參考了！ 首先我們先看看N個人不同的先後順序有幾種組合呢？答案是N!(N階層)種組合，譬如說5個人先後順序的組合方法就有5! = 120種組合，裡面包括第一個人先、然後第二個人、第三個人、第四個人、第五個人執行，也包括第一個人先、然後第三個人、第四個人、第五個人、最後才是第二個人執行，以及更多種組合的方法。因此我們排程的解答，就是在這麼多種組合(N!種)裡面，找到一個執行的順序，大家等待的時間加總起來是最小的。然而要怎麼找到這個解答呢？ 我們可以每一種組合都計算一次總共等待的時間，然後找出等待時間最少的那一次，作為解答。然而這個方法需要N!次的計算！如果今天有10個人，我們不知道要計算幾次(有興趣的人可以計算一下10!有多大)。因此如果有其他經驗改良的搜尋法(Heuristic Search)，會讓我們比較快地找出正確答案，或是雖然不是正確答案，也不會差太多的答案，也是可以，只要找出解答的時間可以接受就好。 作業系統課本裡面CPU Scheduling主要提到了三大種方法：先到先執行 (FCFS: First-Come, First-Served Scheduling)、最短時間的工作先執行 (Shortest-Job-First Scheduling)、以及循環執行(Round-Robin Scheduling)。以下我簡單地用白話來解釋這三種排程的演算法是甚麼樣子。 先到先執行就是說，今天一台機器，先來到機器旁邊的人先用，以此類推。這個方法雖然容易，但是如果其中某一個人要使用機器很久的時間，後面又剛好等了很多人，那麼大家等待的時間總和就會變的很久。 最短時間的工作先執行，則是看看大家的執行時間，需要最少執行時間的人先用機器，以此類推。這個方法是最佳解(optimal)，大家可以用矛盾證法來證明(prove by contradiction)，如果今天我們按照這個演算法，讓執行最少時間的第一位執行、次少時間的第二位執行，以此類推。然後排出來的結果我們說並不是最好的解答，也就是存在一個解答，會和現在的執行順序不同，而且讓執行時間的總和變少。假設是這群人當中的i和j兩個人 (按照剛才的演算法 i 在 j 之前執行) 要交換順序得到最佳解答，變成 j 在 i 之前執行才是最佳解答(等待時間比剛才排程的解答更少)，那麼就表示 j 的執行時間會比 i 的執行時間還短，才有辦法讓新的排程的等待時間總和變少，然而這和一開始的假設矛盾 (按照剛才的演算法，i 之所以排在 j前面，是因為 i 的執行時間比 j 的執行時間少)，因此依照剛才演算法得到的排程，會得到最佳解答。 這個演算法雖然是最佳解，然而因為這個問題是用在不知道每個人究竟會執行多少時間的狀況，所以要找出最短執行時間的人可能有困難，需要用類似移動平均的方法來預測下次可能執行的時間長度。如果每個人使用機器的時間是固定的，而且每個人會執行幾次，以及一開始就知道每次執行的時間是多長，那麼就不需要這邊提到的三大演算法來找出排程順序了！如果使用機器的時間不一樣長，每個人會執行幾次並不一定，每次執行的時間要在執行之前才會知道，這篇文章提到的三種演算法就可以拿來參考看看！ 第三種方法則是循環執行(Round Robin)。這個方法是說，把時間分成一個一個小間隔，譬如說一小時一小時，或是10分鐘為一個單位，大家循序漸進，執行完10分鐘以後就換下一個人，執行完10分鐘以後再換下一個人。如果做個比喻，就好像有10盤菜，每盤菜吃一口，這道菜吃一口就再吃另一道菜，每次都只吃一小口，但是10盤菜最後還是會吃完。這個演算法是分享式的演算法，也就是說如果系統中有50個人，每個人執行時間會變成約50倍，但是就不會有先到先執行演算法的問題，某一個人要執行很久，後面的人就要全部一起等。這個演算法等待時間的總和是多少呢？每個人的等待時間不會超過(n-1)*ti，因此等待時間的總和不會超過 [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Posted By <font color="#008000">Mr. Thursday</font></strong></p>
<p>如果今天有一台機器，N個人要用，每個人使用的時間分別是t1, t2, &#8230;, tn，那麼怎樣子才能讓等待的時間最少呢？如果是以每個人的角度來說的話，當然是先搶先贏啦！不過如果是以這N個人所屬機構的角度來看，要讓<strong>全部人的等待時間</strong>最少，要如何安排使用機器的順序呢？這個時候作業系統 (OS: Operating System) 裡面的<strong>CPU Scheduling</strong>方法，就可以參考了！</p>
<p>首先我們先看看N個人不同的先後順序有幾種組合呢？答案是N!(N階層)種組合，譬如說5個人先後順序的組合方法就有5! = 120種組合，裡面包括第一個人先、然後第二個人、第三個人、第四個人、第五個人執行，也包括第一個人先、然後第三個人、第四個人、第五個人、最後才是第二個人執行，以及更多種組合的方法。因此我們排程的解答，就是在這麼多種組合(N!種)裡面，找到一個執行的順序，大家等待的時間加總起來是最小的。然而要怎麼找到這個解答呢？</p>
<p><span id="more-4802"></span></p>
<p>我們可以每一種組合都計算一次總共等待的時間，然後找出等待時間最少的那一次，作為解答。然而這個方法需要N!次的計算！如果今天有10個人，我們不知道要計算幾次(有興趣的人可以計算一下10!有多大)。因此如果有其他經驗改良的搜尋法(<a target="_blank" href="http://en.wikipedia.org/wiki/Heuristic_(computer_science)">Heuristic Search</a>)，會讓我們比較快地找出正確答案，或是雖然不是正確答案，也不會差太多的答案，也是可以，只要找出解答的時間可以接受就好。</p>
<p>作業系統課本裡面CPU Scheduling主要提到了三大種方法：<strong>先到先執行 </strong>(FCFS: First-Come, First-Served Scheduling)、<strong>最短時間的工作先執行 </strong>(Shortest-Job-First Scheduling)、以及<strong>循環執行</strong>(Round-Robin Scheduling)。以下我簡單地用白話來解釋這三種排程的演算法是甚麼樣子。</p>
<p><strong>先到先執行</strong>就是說，今天一台機器，先來到機器旁邊的人先用，以此類推。這個方法雖然容易，但是如果其中<strong>某一個人要使用機器很久</strong>的時間，<strong>後面又剛好等了很多人</strong>，那麼大家等待的時間總和就會變的很久。</p>
<p><strong>最短時間的工作先執行</strong>，則是看看大家的執行時間，需要<strong>最少執行時間的人先用機器</strong>，以此類推。這個方法是<strong>最佳解</strong>(optimal)，大家可以用<strong>矛盾證法</strong>來證明(prove by contradiction)，如果今天我們按照這個演算法，讓執行最少時間的第一位執行、次少時間的第二位執行，以此類推。然後排出來的結果我們說並不是最好的解答，也就是存在一個解答，會和現在的執行順序不同，而且讓執行時間的總和變少。假設是這群人當中的i和j兩個人 (按照剛才的演算法 i 在 j 之前執行) 要<strong>交換順序</strong>得到最佳解答，變成 j 在 i 之前執行才是最佳解答(等待時間比剛才排程的解答更少)，那麼就表示 j 的執行時間會比 i 的執行時間還短，才有辦法讓新的排程的等待時間總和變少，然而這和一開始的假設矛盾 (按照剛才的演算法，i 之所以排在 j前面，是因為 i 的執行時間比 j 的執行時間少)，因此依照剛才演算法得到的排程，會得到最佳解答。</p>
<p>這個演算法雖然是最佳解，然而因為這個問題是用在不知道每個人究竟會執行多少時間的狀況，所以要找出最短執行時間的人可能有困難，需要用<strong>類似移動平均的方法</strong>來預測下次可能執行的時間長度。<strong>如果每個人使用機器的時間是固定的，而且每個人會執行幾次，以及一開始就知道每次執行的時間是多長，那麼就不需要這邊提到的三大演算法來找出排程順序了！</strong>如果使用機器的時間不一樣長，每個人會執行幾次並不一定，每次執行的時間要在執行之前才會知道，這篇文章提到的三種演算法就可以拿來參考看看！</p>
<p>第三種方法則是<strong>循環執行</strong>(Round Robin)。這個方法是說，把時間分成一個一個小間隔，譬如說一小時一小時，或是10分鐘為一個單位，大家循序漸進，執行完10分鐘以後就換下一個人，執行完10分鐘以後再換下一個人。如果做個比喻，就好像有10盤菜，每盤菜吃一口，這道菜吃一口就再吃另一道菜，每次都只吃一小口，但是10盤菜最後還是會吃完。這個演算法是<strong>分享式</strong>的演算法，也就是說如果系統中有50個人，每個人執行時間會變成約50倍，但是就不會有先到先執行演算法的問題，某一個人要執行很久，後面的人就要全部一起等。這個演算法等待時間的總和是多少呢？每個人的等待時間不會超過(n-1)*ti，因此等待時間的總和不會超過 <u>(n-1)*全部工作時間的總和</u>。有些情況這會比<strong>先到先執行</strong>的演算法好，不過如果工作不能切割，或是換下一個人使用機器的過程成本太高(overhead)，就不適合用這個演算法了。</p>
<p>下圖顯示了不同演算法的排程，用在5個不同時間長短的工作(P1到P5)上面的情形，等待時間的總和必須要<strong>累加</strong>時間才是等待時間的總和，至於工作全部執行完畢的時間則是當然相同的了。FCFS是<strong>先到先執行</strong>演算法，SJF是<strong>最短工作先執行</strong>演算法，RR是<strong>循環執行</strong>演算法，Priotiy本篇文章沒提到，是一種<strong>優先順序</strong>演算法，可以自訂工作的優先順序來排程。</p>
<p style="text-align:center;"><img border="0" width="586" src="http://vrschool.ice.cycu.edu.tw/vrschool/Course/OS/CHAP5/IMG5_5.GIF" height="234" /></p>
<p>排程其實有更多種演算法，用在更多更複雜的情形，譬如從1顆CPU變成多顆CPU的問題，以及每個工作可能有先後順序的限制的問題 (譬如說P3不能排在P1後面等限制條件)。</p>
<p><a target="_blank" href="http://en.wikipedia.org/wiki/Job-shop_problem">Job-Shop Problem</a>就是一個很難的問題，也被證明了是<a target="_blank" href="http://en.wikipedia.org/wiki/NP_complete">NP-complete</a>的問題，就留給有興趣的讀者再進一步去研究吧！希望每個人在遇到有限資源的時候，都能夠找到最佳解的排程 (schedule)！</p>
<p>延伸閱讀</p>
<ul>
<li><a target="_blank" href="http://vrschool.ice.cycu.edu.tw/vrschool/Course/OS/CHAP5/CHAP5.HTM">CPU Scheduling</a> (中文)</li>
<li><a target="_blank" href="http://en.wikipedia.org/wiki/Job-shop_problem">Job-Shop Problem</a></li>
<li><a target="_blank" href="http://en.wikipedia.org/wiki/NP_complete">NP-complete</a></li>
</ul>
<p><br/>
<div>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td><a href="http://plurktop.mmdays.com/replurkdetail/?link=f323707039ccff6a41ac4de8659d8127" title="看看其他人討論內容" target="_blank"><img src="http://plurktop.mmdays.com/images/replurk_1.png" style="border:0"></a></td>
</tr>
<tr>
<td><a href="http://plurk.com/?qulaifier=shares&#038;status=http%3A%2F%2Fmmdays.com%2F2007%2F09%2F28%2Fcpu_scheduling%2F+%28%E6%8E%92%E7%A8%8B%E5%95%8F%E9%A1%8C%E8%88%87CPU+Scheduling%29+-+%E8%BD%89%E5%99%97%E6%8E%92%E8%A1%8C%E6%A6%9C+http%3A%2F%2Fplurktop.mmdays.com%2Freplurk" title="推到噗浪" target="_blank"><img style="border:0" src="http://plurktop.mmdays.com/images/replurk_2.png" /></a></td>
</tr>
</table>
</div>
<p><br/><a href="http://www.facebook.com/MMDays" target="_blank">加入MMDays在facebook的粉絲團 隨時閱讀最新文章</a><br/></p>
]]></content:encoded>
			<wfw:commentRss>http://mmdays.com/2007/09/28/cpu_scheduling/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>遞迴之美: 數學, 電腦科學與碎形</title>
		<link>http://mmdays.com/2007/05/24/recursive/</link>
		<comments>http://mmdays.com/2007/05/24/recursive/#comments</comments>
		<pubDate>Thu, 24 May 2007 04:21:52 +0000</pubDate>
		<dc:creator>mmdays</dc:creator>
				<category><![CDATA[Mr. Saturday]]></category>
		<category><![CDATA[Mr. Thursday]]></category>
		<category><![CDATA[專欄]]></category>
		<category><![CDATA[數學]]></category>
		<category><![CDATA[程式設計]]></category>
		<category><![CDATA[電腦科學]]></category>
		<category><![CDATA[.kkrieger]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[computer graphics]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Fractal]]></category>
		<category><![CDATA[Hanoi Tower]]></category>
		<category><![CDATA[Math]]></category>
		<category><![CDATA[Recursion]]></category>
		<category><![CDATA[Recursive]]></category>
		<category><![CDATA[演算法]]></category>
		<category><![CDATA[碎形]]></category>
		<category><![CDATA[遊戲]]></category>
		<category><![CDATA[遞迴]]></category>
		<category><![CDATA[電玩]]></category>
		<category><![CDATA[電腦圖學]]></category>

		<guid isPermaLink="false">http://mmdays.com/2007/05/24/recursive/</guid>
		<description><![CDATA[想像一下，我剛才說了一句話，那句話是：「想像一下，我剛才說了一句話，那句話是：「想像一下，我剛才說了一句話，那句話是：..........」」，如此下去，就好像站在兩面平行擺設的鏡子中間，鏡子中的影像不斷的重複。再舉個例子，寫完一封信想要匿名保密，就署名「知名不具」。回信的人寫：「知知名不具 具」。之後再回信的時候就變成：知知知名不具具具，加上括號可能比較清楚：(知(知(知名不具)具)具)。]]></description>
			<content:encoded><![CDATA[<p align="left"><strong>Posted By <font color="#008000">Mr. Thursday </font><font color="#000000">&amp;</font> </strong><strong><font color="#964b00">Mr. Saturday<br />
</font></strong><font color="#964b00"></font><font color="#000000">(</font><font color="#ff6600">註：本篇文章有一點長，請耐心服用 XD</font>)<strong><font color="#964b00"><br />
</font></strong></p>
<p><img src="http://mmdays.files.wordpress.com/2007/05/megamonalisa_recursion.jpg" alt="monalisa-recursion" align="left" border="0" />想像一下，我剛才說了一句話，那句話是：「想像一下，我剛才說了一句話，那句話是：「想像一下，我剛才說了一句話，那句話是：&#8230;&#8230;&#8230;.」」，如此下去，就好像站在兩面平行擺設的鏡子中間，鏡子中的影像不斷的重複。再舉個例子，寫完一封信想要匿名保密，就署名「知名不具」。回信的人寫：「知 知名不具 具」。之後再回信的時候就變成：知知知名不具具具，加上括號可能比較清楚：(知(知(知名不具)具)具)。</p>
<p>遞迴就是類似這樣子，不斷的重複同樣的東西，只不過每次重複的是比較小的東西了。大家應該對數學歸納法不陌生，在使用數學歸納法時，我們首先確定 n=1 的時候某件事情是成立，然後在證明 n 到 n+1 的過程是正確的，就可以從 n=1 的例子，一路推論出第 n 項是甚麼東西。就像是推骨牌一樣，把第一張牌推倒了之後，剩下的骨牌自然就被前面的骨牌給推倒。</p>
<p><span id="more-4300"></span></p>
<p>遞迴的概念則是相反的方向：我們想要解決一個大小為 n 的問題，我首先做的事情是把問題化簡成大小為 n-1 的問題，但是解決的方法還是一樣，只不過大小是 n-1。如此繼續化簡，最後變成大小為 n=1 的基本問題，接著只要n=1的基本問題解決了，原來大小為n的問題也跟著解決了。</p>
<p>這又好像層層分工。假設每個人都會加法，然後今天我想求出 1+2+&#8230;+n 等於多少？其中一個辦法就是遞迴，我先假設 1+2+&#8230;+(n-1) 已經有人算好，那麼我只要再加上 n，就可以得到答案了。然而 1+2+&#8230;+(n-1) 要怎麼得到呢？我就請另外一位朋友幫我算。另外一位朋友接到這個問題以後，也用同樣的方法，他把 1+2+&#8230;+(n-2) 的結果交給另外一位朋友算，然後把這個結果加上 (n-1)，就變成我想要的 1+2+&#8230;+(n-1) 了。朋友的朋友也繼續用類似的方法，直到最後一位朋友只需要回答1，接著倒數第二位朋友就把1加上2，傳給倒數第三位朋友，倒數第三位朋友加上3，一直到我收到 1+2+&#8230;+(n-1) 的結果，再加上 n，就大功告成了。
</p>
<p style="text-align: center"><img src="http://mmdays.files.wordpress.com/2007/05/recursion.gif" alt="recursion" border="0" /></p>
<p>不過可能會覺得，如此簡單的問題，為何還需要遞迴呢？其實遞迴也是比較適合一些問題來解，也就是那些「解決方式一樣，但是可以化成大小比較小」的問題，除此之外還可以輕鬆解決基本問題(n=1的時候)。舉例來說，有個古老的問題叫做河內塔 (Hanoi Tower)，問題的定義引述如下 (<a href="http://www.chiuchang.com.tw/toy/hanoi/hanoi.html" target="_blank">引述網站</a>)</p>
<blockquote><p><img src="http://mmdays.files.wordpress.com/2007/05/tower_of_hanoi.jpg" alt="haoi-tower" align="right" border="0" height="187" width="262" />1883年，一位法國的數學家 Edouard Lucas 教授在歐洲的一份雜誌上介紹了一個相當吸引人的難題──迷人的智力遊戲。這個遊戲名為河內塔 (Tower of Hanoi)，它源自古印度神廟中的一段故事 (也有一說是 Lucas 教授為增加此遊戲之神秘色彩而捏造的)。傳說在古老的印度，有一座神廟，據說它是宇宙的中心。在廟宇中放置了一塊上面插有三根長木釘的木板，在其中的一根木釘上，從上至下被放置了64片直徑由小至大的圓環形金屬片。古印度教的天神指示祂的僧侶們將64片的金屬片移至三根木釘中的其中一根上。規定在每次的移動中，只能搬移一片金屬片，並且在過程中必須保持金屬片由上至下是直徑由小至大的次序，也就是說不論在那一根木釘上，圓環形的金屬片都是直徑較小的被放在上層。直到有一天，僧侶們能將64片的金屬片依規則從指定的木釘上全部移動至另一根木釘上，那麼，世界末日即隨之來到，世間的一切終將被毀滅，萬物都將至極樂世界。</p>
<p>倘若這個故事的敘述為真，那麼，我們只需加速移動金屬片，是不是就能愈早到達極樂世界呢？果真要移動這64片金屬片，那麼，至少要花幾次的搬動才能完成呢？有沒有規律可循呢？</p></blockquote>
<p>這個問題，就很符合剛才的特性：我們可以把大問題化成小問題，而且解決的方法相同，只不過問題的大小變小了。另外基本問題(n=1)，就是移動一根金屬片所需要的次數，這個我們也可以輕易解決，所以這個問題就可以用遞迴來解。</p>
<p>首先，我們假設有A、B、C三根柱子，這64片金屬片一開始在柱子A上面，我們想要搬到柱子C。因為問題中規定某個金屬片上面是空的時候才能移動，我們就假設有個人可以幫我們把<font color="BLUE">63片比較小的金屬片先從柱子A搬到柱子B上面</font>，然後我們把<font color="RED">最大的那一片從柱子A搬到柱子C</font>，再請那位朋友把<font color="BLUE">剛才的63片從柱子B搬到柱子C</font>，整個問題就解決了。然後我們只要知道剛才那位朋友搬了幾次，然後加上我們自己般動的1次，就是整個問題要求的搬動次數了。</p>
<p>遞迴不僅僅在數學上有其重要性，在電腦科學之中扮演的角色更是至關重要。程式設計者對於遞迴絕對不會陌生，上面所舉的河內塔問題，實際上也是電腦科學的經典例子之一，是初學程式設計的人一定會學到的東西。遞迴的思維，常常可以讓程式設計者打造出簡潔的程式，讓繁冗的問題透過簡單的程式碼來解決 (例如 parser 的設計)。演算法上所講的 dynamic programming，就是遞迴思維在演算法的具體呈現。</p>
<p><a href="http://mmdays.files.wordpress.com/2007/05/fractal_broccoli.jpg" title="fractal-broccoli"><img src="http://mmdays.wordpress.com/files/2007/05/fractal_broccoli.thumbnail.jpg" alt="fractal-broccoli" align="left" border="0" /></a>遞迴同時也是碎形 (fractal) 這門大學問的基石，碎形是一種相當美妙的幾何圖案，就如同上面那一張蒙娜麗莎的圖一樣，圖中有圖，形中有形，且小的部分都是大的部分的縮影，我們就稱之為碎形。碎形本身的數學定義，實際上就包含了遞迴定義在裡面，我們甚至於可以說，碎形是遞迴在幾何學的一種具體呈現。但是碎形不僅僅是一種數學概念而已，在自然界中，有許許多多的地方都出現自然的碎形，讓人讚嘆遞迴原來就出現在我們的生活周圍。圖中的這棵花椰菜，就蘊含了遞迴的碎形圖案與於其中。碎形同時也在各個研究領域有著廣泛的應用，光是在電腦科學領域，就有人把碎形應用在影像和影片壓縮之上 (這不難想像，由於碎形這種以小見大的特性，我們可以用小的來表現大的，因此可以有壓縮的概念出現)，在電腦圖學上 (computer graphics)，也有人把碎形應用在設計電腦遊戲之中的一些景物，打造出有效率和簡潔的系統。現在電腦遊戲之中的景物，很多都是玩家邊玩、遊戲系統邊產生出即時的景物，這叫做 procedural generation，這種即時產生景物的技術，可以避免遊戲軟體預先儲存一堆要展現的景物，幫整個軟體瘦身。procedural generation 就使用了大量的碎形產生與合成技術於其中，而這些都根植於遞迴這一個深刻卻簡單的思維。</p>
<p>至於把碎形應用在遊戲之中，現在已經做到有多可怕的地步了呢？請大家看看以下的三張圖片，不妨猜猜擁有這種精緻畫面的遊戲軟體，其整個遊戲的size大小是多少呢？</p>
<p align="center"><a href="http://mmdays.files.wordpress.com/2007/05/kkrieger_screenshot_01.jpg" title="kkrieger-screenshot2"><img src="/files/2007/05/kkrieger_screenshot_01.thumbnail.jpg" alt="kkrieger-screenshot2" border="0" /></a> <a href="http://mmdays.files.wordpress.com/2007/05/kkrieger_screenshot_02.jpg" title="kkrieger-screenshot3"><img src="/files/2007/05/kkrieger_screenshot_02.thumbnail.jpg" alt="kkrieger-screenshot3" border="0" /></a> <a href="http://mmdays.files.wordpress.com/2007/05/kkrieger_screenshot_03.jpg" title="kkrieger-screenshot1"><img src="http://mmdays.wordpress.com/files/2007/05/kkrieger_screenshot_03.thumbnail.jpg" alt="kkrieger-screenshot1" border="0" /></a></p>
<p>正確答案是97KB！沒錯，我沒有打錯字，你的眼睛也沒有看錯，這款遊戲的大小只有 97KB！傳統的一片 3.5 吋磁片可以裝下十幾個這款遊戲！這一款第一人稱的射擊遊戲叫做 .kkrieger，是由德國的 <a href="http://en.wikipedia.org/wiki/Demogroup" title="Demogroup">demogroup</a> <a href="http://en.wikipedia.org/wiki/.theprodukkt" title=".theprodukkt">.theprodukkt</a> 所開發，截至目前為止還在beta測試版的階段，這款遊戲之所以可以壓縮到這麼小的境界，就是因為遊戲之中的場景和音樂幾乎全部都是由動態產生，遊戲之中預先存放的資料只有一些簡單的幾何形狀和 MIDI 音樂檔，所以自然檔案大小非常小。如果這款遊戲沒有用 procedural generation 的技巧進來的話，估計檔案大小會爆增成 200~300MB，這樣的技術，真是令人嘆為觀止。而背後最大的功臣，就是這篇文章談到的遞迴和碎形。各位也不妨下載來玩玩看吧 (<a href="http://212.202.219.162/kkrieger#20" target="_blank">下載點</a>)。不過需要注意到一件事情，這款遊戲的載入時間非常長，因為他要靠著一點點的程式碼即時來運算製造出場景，所以要耗去很多計算時間，這可說是一種 time 和 space 的 tradeoff。</p>
<p>看完這篇文章，各位有沒有對看似枯燥的數學有了一點點不同的看法呢？沒想到遞迴可以這樣應用在遊戲開發之中吧。下次學習數學感覺到枯燥時，不妨從應用的角度切入試試看吧！<br/>
<div>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td><a href="http://plurktop.mmdays.com/replurkdetail/?link=22d99f0db208bdd564d2a2635d9c37b8" title="看看其他人討論內容" target="_blank"><img src="http://plurktop.mmdays.com/images/replurk_1.png" style="border:0"></a></td>
</tr>
<tr>
<td><a href="http://plurk.com/?qulaifier=shares&#038;status=http%3A%2F%2Fmmdays.com%2F2007%2F05%2F24%2Frecursive%2F+%28%E9%81%9E%E8%BF%B4%E4%B9%8B%E7%BE%8E%3A+%E6%95%B8%E5%AD%B8%2C+%E9%9B%BB%E8%85%A6%E7%A7%91%E5%AD%B8%E8%88%87%E7%A2%8E%E5%BD%A2%29+-+%E8%BD%89%E5%99%97%E6%8E%92%E8%A1%8C%E6%A6%9C+http%3A%2F%2Fplurktop.mmdays.com%2Freplurk" title="推到噗浪" target="_blank"><img style="border:0" src="http://plurktop.mmdays.com/images/replurk_2.png" /></a></td>
</tr>
</table>
</div>
<p><br/><a href="http://www.facebook.com/MMDays" target="_blank">加入MMDays在facebook的粉絲團 隨時閱讀最新文章</a><br/></p>
]]></content:encoded>
			<wfw:commentRss>http://mmdays.com/2007/05/24/recursive/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
	</channel>
</rss>

