比較排序演算法的簡單介紹和複雜度分析

2021-07-29 21:51:21 字數 3614 閱讀 7118

標題長坑,就拿最近有在用的來弄吧,先寫個大概,以後逐漸完善。

對於以下**,預設包含標頭檔案:

#include

1.氣泡排序(bubble sort)

先從課本上最常見的氣泡排序說起吧,c++**如下(個人習慣介紹演算法使用c++,比偽**還通俗易懂.......)

void bubblesort(int *a, int

n)//

每輪迴圈後,都會把乙個最小的元素放在最左邊不遍歷區

}//i輪後,陣列排序完成

}

在下文中,我會給出實驗測試演算法複雜度的方法,我們不急,我先下結論,氣泡排序的複雜度是o(n^2)。

2.插入排序(insert sort)

從個人角度講,在氣泡排序之後,個人喜歡先介紹插入排序,原因在於,在基本演算法中,實驗證明,insert sort是當n<=9時的最優秀演算法,個人喜歡合併使用quick sort 和 insert sort。

void insertsort(int* a, int

length)

a[i + 1] = key;//

插入key

}}

insert sort 同樣是乙個o(n^2)的演算法。

賦值除了採用這種移動陣列的方法,也可以使用對換插入元素的方法,方法如下:

//

另一種賦值方法

#include void insertsortanother(int a, int

length)

}}

效率:t(n)=t(n-1)+n=t(1)+(1+2+3+...+n-1)=t(1)+n*(n-1)/2(最差情況),是乙個o(n^2)演算法,實際上,式中的n是最差情況,及式前每乙個數都比所選數字大,如果只是亂序微調,n可以降到很小的數,以至於在極限情況下

t(n)=t(n-1)+c=t(1)+c*n,是乙個o(n)演算法,因而insert sort適合對已經基本排好序但是部分退化的資料進行調整。

另外在賦值過程中,可以採用binary search 尋找合適的插入節點來進一步優化演算法,使insert sort在大資料前仍然不太遜色。有時間時我會補充此種插入排序。

3.快速排序(quick sort)

選擇快排作為第三個介紹的演算法,也是因為他在n值足夠大時無與倫比的優越性,這裡有時間我會展開說,先簡單放一下**。

void quicksort(int* a, int low, int

high)

while (j > i && a[j] >=a[high])

swap(a[i], a[j]);

} while (i swap(a[high], a[i]);

quicksort(a, low, i - 1

); quicksort(a, i + 1

, high);

}

快速排序是一種o(nlogn)的排序演算法。當測試資料足夠大時,其將會顯現出無與倫比的優越性,接下來的測試比較中會有說明。

簡單分析一下複雜度:

∵quicksort先從兩邊一起遍歷將陣列遍歷完整的一遍,然後分成兩部分變為兩個子排序,假設兩個自排序的資料規模是a和b

∴t(n)=t(a)+t(b)+a+b

如果a和b很均勻,及a+b+1=n,考慮到數字很大,a+b≈n

t(n)=2*t(n/2)+n

設n=2^k, t(2^k)=2*t(k-1)+2^k

=(2^(k-1))*t(1)+(1+2+4+8+...+k)*(2^k)

=(2^(k-1))*t(1)+1*(1-2*k)/(1-2)*(2^k)

t(n)=(n/2)*t(1)+(2*log(n)-1)*n=n*(t(1)/2+2*log(n)-1)

我們由此得出,在資料均勻(最佳情況)快速排序是乙個o(n*log(n))的演算法。

而在最差情況下,及每次分出的a和b規模都相差懸殊,a=n-1,b=1

t(n)=t(n-1)+t(1)+n=t(1)+(n-1)*(n+t(1))

我們由此得出,在資料極端(最差情況)快速排序是乙個o(n^2)的演算法。

而其他情況,快速排序的效率在這二者之間,因而,pivot的選擇十分重要,如果pivot能盡量讓資料均勻的分布在兩側,則能獲得更高的效率。一種常用的做法是從資料的頭,中,尾各選取乙個數字,並選擇三者的中間值作為pivot,這種做法大幅度的減少了極端資料的可能,但同時也要考慮選取pivot的這個演算法本身的時間和空間消耗。

若不通過pivot選擇來優化,也可以通過根據資料量優化的方法,即當所排列的資料小於10個時,改用對小資料效率更高的insertsort來進行排序(實驗證明,在資料量為9個時,insert sort有著更佳的效率,考慮到被快排後的資料比較整齊,可以考慮在資料量更多時就停止快排),這種方法排除了quick sort遇到極端資料時的尷尬。另一種做法是當快速排序需要處理的資料規模更小時停止快速排序,之後對所有資料進行一次insertsort,因為處理這種幾乎排列完畢的陣列時,insert sort的效率接近o(n)。

當快排到達一定深度後,用堆排序來完成剩下的工作也是一種不錯的選擇,這樣避免了堆排序的最壞情況,使其保持了o(n*log(n))的複雜度,同時避開了快排的小規模資料處理問題。

在允許出現相同數字的一組資料中,產生最壞情況往往是相同資料導致的,即到某個子排序,所有資料都相同,導致快排進行了無意義的操作。一種可行的方案是將資料分為小於pivot,等於pivot,大於pivot三組,考慮到分三組後實現難度大大增加,一種更簡單的替換方法是,每次獲取資料後檢查一下最左端和最右端的資料,如果相等的話就採用其他排序如insert sort來進行處理。

4.歸併排序(mergesort)

#includeconst

int int_max = 100000000

;const

int index_max = 10000

;void mergesort(int* a, int p, int

r)

for (int i = 1;i <= n2;++i)

l[n1 + 1] =int_max;

r[n2 + 1] =int_max;

int i = 1

;

int j = 1

;

for (int k = p;k <= r;++k)

else}}

}

merge sort同樣是一種o(nlogn)的演算法。

5.選擇排序(selection sort)

作為一種被我剛剛遺忘的o(n^2)演算法,還是要說下的,就先給**:

void selectionsort(int *a, int

length)

std::swap(a[i], a[f]);

}}

直接選擇排序的原理是遍歷陣列每乙個位置,將從該位置到結束的所有點中最小的點放置在該位置。

效率:t(n)=t(n-1)+n=t(1)+(1+n-1)*(n-1)/2=t(1)+n*(n-1)/2,是乙個o(n^2)演算法。

演算法複雜度和排序演算法比較

演算法複雜度 時間複雜度 常見的時間複雜度有 常數階o 1 對數階o log2 n 線性階o n 線性對數階o nlog2 n 平方階o n 2 立方階o n 3 k次方階o n k 指數階o 2 n 隨著問題規模n的不斷增大,上述時間複雜度不斷增大,演算法的執行效率越低。空間複雜度 如當乙個演算法...

排序演算法時間複雜度和空間複雜度比較

n 2表示n的平方,選擇排序有時叫做直接選擇排序或簡單選擇排序 排序方法平均時間最好時間最壞時間 桶排序 不穩定 o n o n o n 基數排序 穩定 o n o n o n 歸併排序 穩定 o nlogn o nlogn o nlogn 快速排序 不穩定 o nlogn o nlogn o n ...

各種排序演算法複雜度比較

寫在前面 筆試題目當中會出現各種排序演算法的比較,分為最好,最壞,平均情況的複雜度比較,在這裡總結一下。主要內容 最好情況 一般會這麼問 在各自最優條件下以下演算法複雜度最低的是 看清題目的要求是問在最優的條件下,所以插入排序和氣泡排序是最優的為o n 的複雜度。氣泡排序這裡為啥最好情況時o n 氣...