D C與快速排序 Python實現

2021-10-02 17:53:32 字數 2748 閱讀 8381

我們曾經在證明歐幾里得演算法的正確性時提出過乙個可以抽象並用歐幾里得演算法解決的問題——分土地的問題。現在,我們從乙個更加直觀的角度來看看如何解決這個問題。

在拿到一塊1680×640的土地時,我們想要把它平均劃分成正方形,並且試圖保證正方形面積最大。我們首先將土地劃分出最大的正方形,可以畫出兩塊640×640的土地,剩下一塊400×640的土地。之後我們對剩下的小長方形土地繼續應用這個思路、畫出一塊400×400的正方形土地、一塊400×240的小長方形土地……分到最後,我們將得到一塊160×80的土地,恰好可以完全分成兩塊80×80的正方形土地,而80就是我們要找的答案——問題就這樣被解決了。

仔細思考這個過程,其實這就是歐幾里得演算法的直觀展現,我們的證明也保證了這一過程所得結果得正確性。現在,我們拋開歐幾里得演算法,來看看這個過程得其它特點:

問題的規模被不斷縮小——小長方形土地的面積不斷變小。

有明顯的遞迴特徵——存在基線條件、遞迴條件與乙個反覆使用的方法:劃出正方形土地與小長方形土地。

這個過程就是我們要討論的一種解決問題的方法:分而治之(divide and conquer, d&c)

分而治之的工作原理就是

找出簡單的基線條件。

確定縮小問題規模的方法,使問題最終符合基線條件。

這個演算法並不像我們前面介紹的歐幾里得演算法那樣明確,但這種演算法為我們提供了解決問題的思路。下面,我們先來看看歐幾里得演算法的具體實現,載舉乙個例子看看d&c如何進行,最後我們討論一種優雅快速的演算法——快速排序,來加深對分而治之的理解。

a. 歐幾里得演算法:

關於這個問題我們已經討論了很多了,所以直接給出**:

def

euclidean_algorithm

(numx,numy)

:'歐幾里得演算法'

num_max =

max(numx,numy)

num_min =

min(numx,numy)

if num_max % num_min ==0:

#基線條件。

return num_min

else

:return euclidean_algorithm(num_min,num_max%num_min)

經過測試,**工作良好。

b. 加數字:

假設我們有乙個數字列表,我們想求出這個列表裡所有元素的和。我們可以使用python內建的sum()函式,也可以自己使用乙個簡單的迴圈求和。但是,這裡我們運用分而治之與遞迴的思想。

分而治之要求我們縮小問題規模,遞迴要求我們找到基線條件——什麼樣的列表最好求和?當然是空列表,因為這個和值一定是0。那麼,我們可以減小列表的長度來縮小問題規模,直到達到基線條件。

就像這樣:

def

my_sum

(lt)

:'應用分而治之'

iflen

(lt)==0

:return

0else

:return lt.pop(

)+ my_sum(lt)

經過測試,**工作良好。

一些語言的程式設計方式稱為函式式程式設計——這意味你無法使用迴圈。現在你應該好好想想遞迴了,否則使用這類語言時你可能連求和都無法完成。

下面我們將再次見識d&c,或者說是遞迴的神奇之處:

我們曾經編寫過選擇排序的**,使用了迴圈對列表一次又一次的檢查——讓人感覺思路並不優雅。我們能不能在排序的時候運用我們學到的快速排序呢?

讓我們來想想基線條件——什麼是最簡單的排序呢?當然是只有乙個數字或者沒有數字的列表了,那樣的話我們只需返回這個列表就可以了。

如果不是這種簡單的列表呢?我們需要想乙個簡單的辦法:我們可以選擇第乙個元素作為基準,把所有比基準大的數放到後面,把比基準大的放到後面,然後組合起來就可以了——但是前面和後面的列表是無序的!沒關係,我們把這個問題交給遞迴——我們也使用這種方法對這些無序的列表進行排序就可以了。

這種簡單優雅的思路讓我愛上了遞迴。**也很簡單:

def

quick_sort

(lt)

:'快速排序'

iflen

(lt)

<=1:

return lt

else

: pivot = lt[0]

less =

[i for i in lt[1:

]if i < pivot]

greater =

[i for i in lt[1:

]if i > pivot]

return quick_sort(less)

+[pivot]

+ quick_sort(greater)

我們似乎把一切工作都交給了這個函式自己,但出乎意料的是工作的很完美:

lt =[3

,8,9

,5,4

,6,7

,1,2

]print

(quick_sort(lt)

)

結果是

[1,

2,3,

4,5,

6,7,

8,9]

這就像我們用簡陋的幾行遞迴**解決複雜的無與倫比的漢諾塔問題時所感到的驚訝與驚喜!

之後我們還會討論快速排序——我們將討論它的執行時間。但這篇文章中我們的主題是遞迴,所有就到此結束了。

D C與快速排序

d c的意思是分而治之,它是一種著名的遞迴式問題解決方法。使用d c來解決問題的過程包括兩個步驟 1 找出基線條件,這種條件必須盡可能簡單 2 不斷將問題分解 或者說縮小規模 直到符合基線條件 求列表 2,4,6 的和 1 找出基線條件。列表中不包含元素 2 縮小問題規模。將求列表 2,4,6 的和...

python實現快速排序

快速排序的思想是任意選取要排序的list中的乙個數pivot,每次遞迴時將list按照 小於pivot的,pivot,大於pivot的 排序,再對小於和大於pivot部分分別快速排序。function quicksort list select a pivot foreach x in list i...

Python實現快速排序

快速排序的思路 numlist 6,8,1,4,3,9,5,4,11,2,2,15,6 1 設 keys 又稱為監視哨 等於 numlist 0 i等於0 j等於len numlist 1,即如下 numlist 6,8,1,4,3,9,5,4,11,2,2,15,6 keys 6 i 0 j2 1...