演算法導論 1 排序演算法

2022-02-13 13:14:59 字數 2951 閱讀 2325

排序演算法是最基礎的一類演算法。主要排序演算法包括選擇排序、插入排序、氣泡排序、合併排序、堆排序和快速排序。把這些排序演算法全部實現一邊,再把《演算法導論》對應章節後面的習題做一遍,確實是系統學習演算法的乙個不錯的開端。

選擇排序的想法很簡單,把需要排序的陣列看成一堆撲克牌:先查一遍,抽出最小的作為第乙個張;在剩下的牌堆裡再查一遍,選出最小的作為第二個元素……重複直到牌堆耗盡。想法簡單的其代價就是執行時間為θ(n×n):在查詢a、2或3的時候,都要反覆地比較其與k、q的大小,直覺告訴我這樣做沒有意義。

void selectionsort(int* x, int

length)

}int temp =x[minposition];

x[minposition]=x[i];

x[i]=temp;

}}

插入排序的想法類似於從牌堆中摸牌,並插入到手中已經排序過的牌中。在最外層以i為自變數的迴圈中,0~i-1張牌就是手中已排序的牌(迴圈開始時就是第一張牌x[0]),i~length-1張牌就是牌堆,每次迴圈將第i張牌(也就是牌堆頂部的第一張牌)插入到牌堆中。因為手中的牌已經排好序,所以每次插入都會移動所有比這張待插入的牌大的手牌。這個排序演算法的執行時間也很高,為θ(n×n)。

void insertionsort(int* x, int

length)}}

}

合併演算法是一種遞迴的演算法。假設牌堆已經分成兩堆,每一堆都已經排好序,比如一堆是,另一堆是,把這兩堆合併成乙個牌堆的方法很簡單,只要依次比較兩個牌堆頂部的牌,選擇較小的一張加入已排序的牌堆,直到兩個牌堆都空了,這個工作的時間代價僅為θ(n)。如何獲得已排序的兩個牌堆呢?答案是先直接均分為兩堆,再遞迴地呼叫自身去對著兩堆合併排序,直到問題的規模足夠小,比如只剩1張或2張牌。好在將問題分解到足夠小需要的遞迴次數是lgn而不是n,因此該演算法的執行時間為θ(n×lgn)。不過合併排序需要額外的空間開銷,換言之它不是一種原地排序演算法,他的空間開銷為θ(n×lgn),而原地排序演算法僅僅為θ(n)。

void mergesort(int* x, int

length)

int mid = (length-1)/2

;

int child1size = mid+1

;

int* child1 = new

int[child1size];

int child2size = length-mid-1

;

int* child2 = new

int[child2size];

for(int i=0;i1;i++)

for(int i=mid+1;i)

mergesort(child1,child1size);

mergesort(child2,child2size);

if (j==child2size)

if(child1[i]<=child2[j])

if(child2[j]}

}return

;}

氣泡排序是乙個很簡單的原地排序方法:從陣列的最後乙個元素開始(這個元素就是當前的「泡」)向前遍歷,如果前乙個元素比當前的「泡」小,那麼當前的「泡」就變成了前乙個元素;如果前乙個元素比當前的「泡」大,那麼交換「泡」和該元素的位置(這個「泡」冒上去了)。每一次冒泡到最前面乙個元素,都能保證選擇了最小的「泡」。雖然該演算法執行時間為θ(n×n),但是在冒前面的「泡」的過程中,後面的相對較小的元素也一定程度地冒上來了(換言之,這次冒泡並不是「無用功」),使得冒比較大的「泡」時經常只需要檢查一下而不用作交換,所以常數因子比較小。

void bubblesort(int* x, int

length)}}

}

堆排序是一種「漂亮」的原地排序方法,其執行時間為θ(n×lgn)。熟悉了最大堆的特性,堆排序的思路就非常簡單了:最大堆的根節點最大,將根節點和堆中的最後乙個元素互換位置,並且將堆的長度減去1;此時堆已經不是最大堆,但是根元素的兩個子堆仍然是最大堆,將這種堆轉化為最大堆的過程heapmax只需要θ(lgn)時間,那麼就轉化為最大堆再取次大的元素。由乙個雜亂陣列建成乙個最大堆的過程heapmaxbuild也需要θ(n×lgn)時間,這不影響總的執行時間量級。

void heapmax(int* xinput, int xsize, int

i)

if(l>=xsize && r>=xsize)

if(xinput[i]>=xinput[l] && (r>=xsize ? true : (xinput[i]>=xinput[r])))

int maxi=(r>=xsize ? l : (xinput[l]>xinput[r]?l:r));

int temp =xinput[i];

xinput[i]=xinput[maxi];

xinput[maxi]=temp;

heapmax(xinput, xsize, maxi);

}void heapmaxbuild(int* x, int

length)

}void heapsort(int* x, int

length)

}

快速排序的執行時間為θ(n×lgn),它是一種原地排序演算法。取最後乙個元素作為基準,遍歷一次陣列,將小於基準的元素排在前面,大於基準的元素排在後面,而不在乎同小於或同大於基準的元素之間的順序。一次遍歷之後,將最後乙個元素和大於基準的元素的第乙個交換位置,則基準前方的都是小於基準的元素,後方都是大於基準的元素,再遞迴呼叫自身,對同小於或同大於基準的元素進行快速排序。

int partition(int* x, int p, int

r) }

int tmp =x[i];

x[i]=x[r];

x[r]=tmp;

returni;}

void quicksort(int* x, int p, int

r)}

演算法1 排序

氣泡排序 氣泡排序,比較相鄰的元素由小到大排序 function bubblesort arr return arr view code 快速排序 以基數為標準,最右開始查小於基數停止,最左邊開始查大於基數停止,互換位置停止的位置 left right表示基數左為小於基數,基數右大於基數的 拆分基數...

演算法 排序1 排序

題目 給定n個 長整型範圍內的 整數,要求輸出從小到大排序後的結果。本題旨在測試各種不同的排序演算法在各種資料情況下的表現。各組測試資料特點如下 輸入第一行給出正整數n 10 5 隨後一行給出n個 長整型範圍內的 整數,其間以空格分隔。在一行中輸出從小到大排序後的結果,數字間以1個空格分隔,行末不得...

演算法小白 1 排序演算法

穩定 排序前a位於b前,且a b,排序完後a仍然位於b前。不穩定 排序前a位於b前,且a b,排序完後a可能位於b後。內排序 所有排序操作都在記憶體中完成 外排序 由於資料太大,因此把資料放在磁碟中,而排序通過磁碟和記憶體的資料傳輸才能進行 時間複雜度 乙個演算法執行所耗費的時間。空間複雜度 執行完...