NO.2 嘗試探究python的經典算法-快速排序(一)分而治之

首先要確定快速排序的核心思想就是分而治之,其中需要對遞歸的一定理解,我也只是嘗試去深入理解一下。
首先是假設我們有兩個數,我們要找出他們的最大公約數
最大公約數(greatest common divisor(gcd)):即能夠同時被兩個數整除的那個最大的數。例如:8是16和8的公約數,因爲16%8和8%8都等於零嘛!但4也是啊!所以兩個數的公約數會有很多,但我們要找出那個最大的!
如果這兩個數是10和5 ,那我們可以很快看出他們之間的最大公約數是5
那如果這兩個數是·64和168呢,首先,64是不可能的了,那我們就需要往下繼續找
在計算之前這其中我們需要確立兩個條件:
1.找出基線條件,這個條件必須儘可能簡單
2.不斷將問題分解,知道符合基線條件
回到我們的64和168,其中有個簡單的python寫法,那就是用循壞遍歷所有小於他們的整數,將最大的那個能被這兩位數都整除的數字留下,代碼如下:

def gcd(x,y):
    for i in range(1,y+1):
    #默認y值小於x值
        if x%i==0 and y%i==0:
            j=0
            if i>j:
                j=i
    return j

這種方法其實是可行的,但這樣解法在大數據前很慢,有略過粗暴,所以這裏有一個經典的算法叫歐幾里得算法:
1.先假設x>y,x和y的最大公約數用f表示
2.假設 x/y = a,x%y = b;所以:a*y + b = x
(這個應該能看出來,因爲a爲x除以y的整數部分,b爲x除以y的餘數部分,所以a*y + b = x)
也就是168=64*2+40
將上面那個式子調換一下位置得到:b = x – a*y;
也就是 40=168-62*2
因爲x和y都能夠被f整除 —–因爲f是x和y的最大公約數嘛
所以 b 也能夠被f整除 —–即x和y的最大公約數f,它也是b的約數,所以求x和y的最大公約數也就相當於求y和b的最大公約數。
(你可能會問,爲什麼本來求x和y的最大公約數,最後轉了半天變成了求y的b的公約數了?因爲 y < x嘛,而且x%y肯定也小於y,所以,這樣一來,我們就把求最大公約數的範圍縮小了)
所以、歐幾里得的公式也就是這麼來的x , y = y , x%y;
所以這個算法的實現也就是不停的迭代,直到找出了x%y等於0時,則停止迭代,那個時候最大公約數也就是y了(因爲x%y都等於0了,所以x和y的最大公約數也就是y本身了)。
用代碼寫出來十分簡潔:

def gcd(a, b):
    while a != 0:
        a, b = b % a, a
    return b

我們看出來歐幾里得算法的核心思路也是我上面提到過的兩點:
1.找出簡單的基線條件
2.確定如何縮小問題的規模,使其符合基線條件
再來去一個例子,有一個列表 【2,4,6】
你需要將這些數字相加,使用循壞就可以很快完成:

def sum(list):
    total=0
    for i in list:
        total+=i
    return total

但我們試着使用遞歸函數來完成:
第一步,找出基線條件,
最簡單的列表是怎麼樣的呢?如果一個列表是空的或者是隻有一個數那就簡單很多,答案就是0或者那唯一的那個數,因此這就是基線條件
第二步,縮小問題的規模,每次遞歸都離我們的基線條件更進一步,那就是離空數組更進一步
先構思一下思路,如果我用 2 + sum([4,6]) ,下一步在計算 2+10,是不是就簡單很多了,那我們將後一步分解成4+sunm([6])呢,再細分一步,6+sunm([]),當後一步爲一個空數組後,我們就達成了我們的基線目標,我們就在這種分而治之,也就是遞歸的思想下解決了問題。
代碼如下:

def sum(list):
    if list==[]:
        return 0
    return list[0]+sum(list[1:])

這也是使用遞歸函數的一個思想,直接或間接的調用自身的方法。
遞歸方法實際上體現了“以此類推”、“用同樣的步驟重複”這樣的思想,用簡單的程序來解決某些複雜的計算問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章