iT邦幫忙

2021 iThome 鐵人賽

DAY 12
0

排序的速度

Quicksort,需要https://chart.googleapis.com/chart?cht=tx&chl=%5CTheta(nlgn)
heapsort,需要https://chart.googleapis.com/chart?cht=tx&chl=%5CTheta(nlgn)
merge sort,需要https://chart.googleapis.com/chart?cht=tx&chl=%5CTheta(nlgn)
insertion sort,需要https://chart.googleapis.com/chart?cht=tx&chl=%5CTheta(n%5E2)

在前幾天的時間我們看到了這一些演算法,我們發現他們最快時間都在https://chart.googleapis.com/chart?cht=tx&chl=%5CTheta(nlgn),那有沒有可能有一個演算法它的速度是快過於https://chart.googleapis.com/chart?cht=tx&chl=%5CTheta(nlgn)的?

我們會發現這上面四種排序的演算法都有一個性質,就是透過比較兩個元素的大小關係來做出排序,也就是它們是基於同樣的一種演算法模型去設計的演算法,而在這個演算法模型底下,https://chart.googleapis.com/chart?cht=tx&chl=%5CTheta(nlgn)是我們能夠達到的最快速度。

比較排序的演算法模型,決策樹

在這個演算法模型中,規範了我們能夠對兩個元素a和b進行怎樣的操作,像是我們可以執行https://chart.googleapis.com/chart?cht=tx&chl=a%20%3C%20b, https://chart.googleapis.com/chart?cht=tx&chl=a%3C%3Db, https://chart.googleapis.com/chart?cht=tx&chl=a%3Db, https://chart.googleapis.com/chart?cht=tx&chl=a%3E%3Db, https://chart.googleapis.com/chart?cht=tx&chl=a%3Eb這些操作,如果我們對整數集合進行排序,我們只能對元素進行比較的操作,不能做出相加,相乘等等在這個演算法模型規範以外的操作。

關於透過比較方式進行的排序,我們可以使用決策樹來表示他,決策樹是一顆完全二元樹,他可以表示給定固定大小的輸入,產生出所有可能排序情況。

假設給定陣列https://chart.googleapis.com/chart?cht=tx&chl=A%20%3D%20%5Cbegin%7BBmatrix%7D%20a_1%2C%20a_2%2C%20a_3%20%5Cend%7BBmatrix%7D

從樹根開始看,比較https://chart.googleapis.com/chart?cht=tx&chl=a_1https://chart.googleapis.com/chart?cht=tx&chl=a_2
如果https://chart.googleapis.com/chart?cht=tx&chl=a_1%20%3E%20a_2,就https://chart.googleapis.com/chart?cht=tx&chl=a_1https://chart.googleapis.com/chart?cht=tx&chl=a_3進行比較。
如果https://chart.googleapis.com/chart?cht=tx&chl=a_1%20%3C%3D%20a_2,就https://chart.googleapis.com/chart?cht=tx&chl=a_2https://chart.googleapis.com/chart?cht=tx&chl=a_3進行比較。

給定陣列https://chart.googleapis.com/chart?cht=tx&chl=A%20%3D%20%5Cbegin%7BBmatrix%7D%206%2C%208%2C%205%20%5Cend%7BBmatrix%7D,我們想要產生出由小到大的排列,整個決策樹的走法如下

最終產生出的組合為(3,1,2),即為由小到大的排列方式。

在決策樹中,每一個內部節點都是以https://chart.googleapis.com/chart?cht=tx&chl=i%3Aj標記,其中https://chart.googleapis.com/chart?cht=tx&chl=1%3C%3Di%2C%20j%20%3C%3Dnhttps://chart.googleapis.com/chart?cht=tx&chl=n維陣列中元素的個數。每個內部節點會分出兩顆子樹,左子樹表示https://chart.googleapis.com/chart?cht=tx&chl=a_i%20%3C%3D%20a_j所需要進行的後續比較,右子樹表示https://chart.googleapis.com/chart?cht=tx&chl=a_i%20%3E%20a_j所需要進行的後續比較。對於一個正確的比較排序演算法,https://chart.googleapis.com/chart?cht=tx&chl=n個元素的陣列會產生出https://chart.googleapis.com/chart?cht=tx&chl=n!種排列的情況,也就是產生出https://chart.googleapis.com/chart?cht=tx&chl=n!個葉節點。

上面提及的四種演算法都可以使用決策樹的方式進行表示,但一般來說不會那麼做,原因為考慮一般性,也就是考慮排序長度為https://chart.googleapis.com/chart?cht=tx&chl=n的陣列,會有https://chart.googleapis.com/chart?cht=tx&chl=n!個節點,導致樹長的非常大一棵,因此一般描述演算法時會採用虛擬碼的方式進行描述。

使用決策樹的好處,在於我們可以直觀的分析對於長度為https://chart.googleapis.com/chart?cht=tx&chl=n的陣列,排序所需要的執行時間與最差情況。

執行時間與最差情況

從樹根到任一葉節點之間的路徑長度,表示排序演算法所需要進行比較的次數,也就是執行時間,可以表示成樹的深度。而最壞情況就是樹根到葉節點最長的路徑長度,也就是樹的高度,有最多的比較次數。

我們要證明在這個比較模型底下,沒有任何一種演算法是要比https://chart.googleapis.com/chart?cht=tx&chl=%5CTheta(nlgn)還要快的,也就是最長路徑的最小值為https://chart.googleapis.com/chart?cht=tx&chl=%5COmega(nlgn)

證明: 對於長度為n的陣列所繪製出的決策樹,其樹高為https://chart.googleapis.com/chart?cht=tx&chl=%5COmega(nlgn)
對於長度為n的陣列所繪製出的決策樹,其擁有https://chart.googleapis.com/chart?cht=tx&chl=%3E%3Dn!個節點,令決策樹的高度為https://chart.googleapis.com/chart?cht=tx&chl=h,葉子數量為https://chart.googleapis.com/chart?cht=tx&chl=l,則最多擁有https://chart.googleapis.com/chart?cht=tx&chl=2%5Eh個葉節點,因為這是一棵二元樹,每個節點都有兩個分支,因此我們可以得出下面關係式
https://chart.googleapis.com/chart?cht=tx&chl=n!%20%3C%3D%20l%20%3C%3D%202%5Eh,對兩邊式子取對數
https://chart.googleapis.com/chart?cht=tx&chl=lg(n!)%20%3C%3D%20lg(l)%20%3C%3D%20h (因為https://chart.googleapis.com/chart?cht=tx&chl=lg為單調遞增函數,因此可以做這樣的操作)
根據Stirling's formula,https://chart.googleapis.com/chart?cht=tx&chl=n!%20%5Capprox%20%5Csqrt%20%7B2%5Cpi%20n%7D(%5Cfrac%20n%20e)%5En用來取https://chart.googleapis.com/chart?cht=tx&chl=n!的近似值
https://chart.googleapis.com/chart?cht=tx&chl=lg(%5Csqrt%20%7B2%5Cpi%20n%7D(%5Cfrac%20n%20e)%5En)%20%3C%3D%20lg(l)%20%3C%3D%20h
https://chart.googleapis.com/chart?cht=tx&chl=nlg(%5Csqrt%20%7B2%5Cpi%20n%7D(%5Cfrac%20n%20e))%20%3C%3D%20lg(l)%20%3C%3D%20h
https://chart.googleapis.com/chart?cht=tx&chl=n(lg%5Csqrt%20%7B2%5Cpi%20n%7D%20%2B%20lg%5C%20n%20-%20lg%5C%20e)%20%3C%3D%20lg(l)%20%3C%3D%20hhttps://chart.googleapis.com/chart?cht=tx&chl=lg%5C%20ehttps://chart.googleapis.com/chart?cht=tx&chl=lg%5Csqrt%20%7B2%5Cpi%20n%7D為常數,當n趨近於無限時可以忽略不計
https://chart.googleapis.com/chart?cht=tx&chl=n(lg%5C%20e)%20%3C%3D%20lg(l)%20%3C%3D%20h
https://chart.googleapis.com/chart?cht=tx&chl=%5COmega(nlgn)%20%3C%3D%20lg(l)%20%3C%3D%20h%20

結論: 對於使用比較大小方式進行排序的演算法,皆可以對應到決策樹,並且效率都不會好過於https://chart.googleapis.com/chart?cht=tx&chl=%5COmega(nlgn),而heapsort,merge sort和隨機化的quicksort他們執行時間的上界為https://chart.googleapis.com/chart?cht=tx&chl=O(nlgn),恰好對應到決策樹的下界。隨著n的增長,heapsort,merge sort隨機化的quicksort會漸進式的趨近於在決策樹模型下的最優解,也就是貼近他的下界。

突破模型的限制,線性時間的排序法

線性時間幾乎是我們可以得到的最有效率結果(不考慮平行化處理或是一些情況),因為我們至少需要遍歷過整個數據。

如何在線性時間內完成排序,要突破模型的限制,就是我們不在比較元素的大小,對元素做其他的操作,也就是讓這個演算法不被這個模型所包含,那這個演算法就有機會達到線性時間內的排序了。

參考資料:Introduction to algorithms 3rd


上一篇
Day-11 priority queue
下一篇
Day-13 線性時間演算法 : Counting sort
系列文
從0開始啃Introduction of algorithms心得與記錄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言