演算法學習 2

2021-07-26 05:05:34 字數 2885 閱讀 1195

當我們在沒有學習演算法之前,在做排序問題的時候,首先想到的應該是選擇排序或者是氣泡排序。其中選擇排序可能是大腦最自然的思考方式。

很小的時候上體育課,在操場上,同學們零零散散站著,老師掃了一眼,叫了最高個同學站在到前面,然後再在剩餘同學中選擇最高的依次站成一排,重複此過程直到最後乙個同學也站入隊伍了後,隊伍也就按高矮順序排好了,自此我們潛意識的學習了選擇排序法。一碰到排序問題,潛意識的聯想到這種排序方式。

在我們進入高中或者大學,長大懂事了,上體育課時知道要站成一排一排,但一開始由於都喜歡跟自己玩的好的夥伴站在一起,站成的佇列並沒有按高低順序站好。這時老師也變懶了,不會再乙個個指定位置站了,只會說一句,你們按高矮順序排列。我們就自個看看左右,如果右邊的比自己矮就跟他換乙個位置,這樣過了一會隊伍就按右到左從高到矮順序排好了。這種排序方法差不多就是氣泡排序。

**於實際生活中的體驗能很好的被大腦所參考,所以我們在寫排序演算法,估計大多數人會寫出這兩種方法,而對於像插入排序,歸併排序等等演算法要是沒有經過一定的訓練和深入的了解,就算當時學會了,過了一段時間,想要寫出來應該會很難。

以上都是題外話,進入主題,寫出歸併排序的偽**:

歸併排序是一種採用分治策略的排序方法,分治策略是學習演算法的乙個入門級的方法,講起來很簡單,當乙個問題的求解過程規模比較大,步驟比較多的時候,把它拆分成2個或多個規模較小但是跟原問題一樣的問題,然後分別求解,並把結果合併得到未拆分前問題的答案。把拆分後的子問題,重複這個過程,就是書面上說的遞迴操作,就可以把真正需要求解的問題分解成規模極小的問題,這些問題的答案往往是顯然的。

如果只是會說出分治策略的思想,就覺得自己能很好的寫出歸併排序程式,就有點圖樣圖森破了。

下面就按照上面表述的思路來試著寫偽**

//排序a[1,..,n]//merge_sort是乙個procedure,是乙個函式,是我們需要編寫的函式,同時我們也要告訴自己他是乙個已經實現的函式,他可以正確的排序傳給它的陣列引數。

merge_sort(a)

n = a.length

if n==1

return

//只有乙個元素,必然是排好序的,也不需要分解成子問題求解,因此返回

else

//從中間等量分解為2個規模差不多的需要排序的陣列,

a1 = a[1,..,n/2]

a2 = a[n/2+1,..,n]

//排序a1,a2

merge_sort(a1)

merge_sort(a2)

//a1,a2已排序,合併結果

k=1,i=1;j=1

for k = 1

to n

if i<=a1.length

and a1[i] <= a2[j]

a[k] = a1[i]

i = i+1

else

a[k] = a2[j]

j = j+1

//合併結束,a已經排好序

通過實踐以後可知分治法最難的部分應該在合併結果上,這也是需要我們自己去思考程式設計最多的一部分。

下面貼出書本上的偽**,從而可以比較一下自己寫的**有哪些不足及不好的地方

merge_sort(a,p,r)

if p < r

q = (p + r)/2

merge_sort(a,p,q)

merge_sort(a,q+1,r)

merge(a,p,q,r)

merge(a,p,q,r)

n1 = q - p + 1

n2 = r - q

let l[1..n1+1] and r[1..n2+1] be new array

fori=1 to n1

l[i] = a[p+i-1]

forj=1 to n2

r[j] = a[q+j]

l[n1+1] = ∞

r[n2+1] = ∞

i=1j=1for k=p to r

if l[i]

<= r[j]

a[k] = l[i]

i=i+1

else

a[k] = r[j]

j=j+1

合併部分單獨抽出來處理,可見編寫歸併排序演算法主要實現的邏輯**還是在歸併操作,分治策略只是乙個遞迴結構,了解就很簡單。

該例程更加一般化,不但可以排序整個陣列a(p=1,r=a.length),也可排序a的部分元素,在偽**的編寫上也更加清晰易懂。在合併操作中使用了乙個小技巧,在兩個子陣列後面插入了乙個哨兵元素防止對陣列取值的時候越界。

再看出之前寫的**會發現出現陣列越界問題

for k = 1

to n

if i<=a1.length

and a1[i] <= a2[j]

a[k] = a1[i]

i = i+1

else

a[k] = a2[j]

j = j+1//當a1中最後乙個元素最大時,a2把最後乙個元素插入到a中後,會執行到這,然後在最後一次迴圈k=n時,a2[j]越界

修改:

for k = 1

to n

if j > a2.length

//防止越界

a[k] = a1[i]

i = i+1

else

if i > a1.length

//防止越界

a[k] = a2[j]

j = j+1

else

if a1[i] <= a2[j]

a[k] = a1[i]

i = i+1

else

a[k] = a2[j]

j = j+1

雖然正確,**不夠優雅簡潔。

不要以為你會實現幾個功能就說你會開發,會程式設計。

演算法學習 2

題目要求 乙個數如果恰好等於它的因子之和 包括1,但不包括這個數本身 這個數就稱為 完數 例如28的因子為1,2,4,7,14,而28 1 2 4 7 14.因此28是 wan shu 完數.編寫演算法找出1000之內的所有完數,並按下面格式輸出其因子 28 it s factors are 1,2...

STL演算法學習2

二 變異演算法 是一組能夠修改容器元素資料的模板函式。copy v.begin v.end l.begin 將v中的元素複製到l中。1元素複製copy include include include include using namespace std void main 2元素變換transfo...

SIFT演算法學習(2)

3.sift sift全稱為 scale invariant feature transform 即尺度不變特徵變換。sift演算法提取的 sift 特徵具有如下特性 sift特徵是影象的區域性特徵,其對旋轉 尺度縮放 亮度變化保持不變性,對視角變化 放射變換 雜訊也保持一定程度的穩定性。獨特性好,...