經典排序演算法 C 版(上)

2022-01-15 00:57:14 字數 3868 閱讀 5738

提起排序,與我們的息息相關,平時開發的**少不了排序。

經典的排序演算法又非常多,我們怎麼評價乙個排序演算法的好壞呢?

其實可以這樣想,要細緻的比較排序演算法好壞,那我們就從多方面盡可能詳細的對比

一、效率方面

1、排序演算法的執行效率:最好、最壞、平均

2、 我們之前捨棄的時間複雜度的係數、常量、低階,在這裡需要拿回來

3、排序,免不了比較和移動

二、記憶體消耗方面

沒錯就是 演算法的空間複雜度,不過對於排序的空間複雜度來說,又賦予了新的名詞 — 原地排序。

顧名思義是 原地排序的肯定是消耗記憶體少,反之需要往外走幾步那就需要臨時申請記憶體了。

原地排序 = o(1)

三、演算法穩定性

字面意義就是不論怎麼擺弄,這個演算法穩定,不會對順序有影響。

舉個例子:有兩個物件,其中的金額字段一樣,按照金額排序,經過演算法一頓折騰後,相同金額的物件先後順序不能發生改變。

講完評估排序演算法的優劣的幾個方面,那就直接看看我們平時常見的幾個經典演算法:

1、氣泡排序

圖例演示

//排序 — 氣泡排序

2private

static

void bubblesort(int

source)3"

);22}23

if (!ischanged)

24break;25

}26printf(source);

27 }

q:氣泡排序的時間演算法複雜度a:最壞時間複雜度 — o(n^2):迴圈 n*n次

最好時間複雜度 — o(n)    :迴圈 n次即可

平均時間複雜度 — o(?)

這裡我們使用概率來分析平均複雜度,情況比較複雜。

我們使用一種新的概念來分析平均複雜度,這個就是 有序度。

有序度:看作是向量,左<= 右

逆序度:正好相反,左 >= 右

滿有序度 = n*(n-1) / 2

逆序度 = 滿有序度 - 有序度

對於 n 個資料來說,最壞情況時間複雜度的有序度是0,要交換 n*(n-1)/2次才能正確輸出。

對於最好情況複雜度的有序度是n*(n-1)/2,需要交換0次就能達到完全有序。

最壞 n*(n-1)/2次,最好0次,取個中間值來表示中間情況,也可以看作是平均情況 n*(n-1) /4

所以平均下來 要做 n*(n-1) / 4 次才能有序,因為氣泡排序的時間複雜度的上限是 o(n^2)

所以平均情況時間複雜度為 o(n^2)

雖然這樣推論平均個情況並不嚴格,但是比起概率推論來說,這樣簡單且有效。

q:氣泡排序是不是原地排序

a:是,臨時變數為了交換資料,常量級別的臨時空間申請,所以空間複雜度為o(1)

q:氣泡排序是不是穩定排序

a:是,因為沒有改變相同元素的先後順序。

2、插入排序

假定,我們將排序串分為兩個區:已排序區,未排序區

乙個元素要找到正確的的位置進行插入,那麼需要去已排序區域找到自己的位置後,

將這個位置的元素們向後移動,空出位置,然後新元素入坑。

從以上這個思路來看,插入排序也是涉及到了元素的比較和移動。

給我們乙個無序陣列,哪塊是已排序區?**是未排序區?

比如:9, 0, 1, 5, 2, 3, 6

初始時,9 就是已排序區域;

0開始去已排序區域挨個比較,即 i=1,0<9,9向後挪動,空出位置,0入坑;

1開始去 [ 0,9 ] 已排序區域比較,1 < 9,9向後移動騰位置,1入坑,1 > 0 無需操作;

依次重複以上操作,即可達成有序。

圖例演示

//排序 — 插入排序

2private

static

void insertionsort(int

source)320

21//

後移22source[j + 1] = source[j];

23}24

25//

入坑26

source[j + 1] = sorting;27}28

printf(source);

29 }

q:插入排序的時間演算法複雜度a:最壞時間複雜度 — o(n^2):完全倒序,迴圈n次,比較n次

最好時間複雜度 — o(n):完全有序,迴圈n次跳出

平均時間複雜度 — o(n^2):迴圈 n次資料,在乙個陣列中插入資料的平均情況時間複雜度為o(n),所以是 o(n^2)

q:插入排序是不是原地排序

a:是,沒有臨時變數申請,所以空間複雜度為o(1)

q:插入排序是不是穩定排序

a:是, if (sorting >= source[j]) 這個判斷保證了相同元素的先後順序不變,

去掉等於號也可以發生改變。可以實現穩定排序所以說是穩定排序

開始我們也說了,這麼多排序演算法,我們要對比一下,擇優選擇。

排序最好情況

最壞情況

平均情況

是否穩定

是否原地

冒泡o(n)

o(n^2)

o(n^2)是是

插入o(n)

o(n^2)

o(n^2)是是

那麼問題來了平均都是 o(n^2),為什麼傾向於使用插入排序呢?

這兩種排序我們將常量都放進來會發現,冒泡使用的常量數比排序多,所以在資料量上來後  常量*n 會有很大的差距。

我們的程式語言中的排序演算法很多都會傾向於插入排序演算法。

3、選擇排序

其實操作類似於插入排序,只不過是換了換操作方式。

所以也分為 已排序區和未排序區,操作方式是在未排序區間找到最小的,然後放到已排序區間最後。

圖例:

> c#

private

static

void selectionsort(int

source)

}if (i !=minindex)

}printf(source);

}

q:選擇排序的時間演算法複雜度a:最壞時間複雜度 — o(n^2)

最好時間複雜度 — o(n^2)

平均時間複雜度 — o(n^2)

q:選擇排序是不是原地排序

a:是,沒有臨時變數申請,所以空間複雜度為o(1)

q:選擇排序是不是穩定排序

a:不是

4、對比 隨機生成1000個元素的 int 陣列

分別執行時間如下:

經典排序演算法(Java版)

1 氣泡排序 bubble sort 最簡單的排序方法是氣泡排序方法。這種方法的基本思想是,將待排序的元素看作是豎著排列的 氣泡 較小的元素比較輕,從而要往上浮。在氣泡排序演算法中我們要對這個 氣泡 序列處理若干遍。所謂一遍處理,就是自底向上檢查一遍這個序列,並時刻注意兩個相鄰的元素的順序是否正確。...

經典排序演算法 java版

交換排序 氣泡排序 快速排序 選擇排序 直接選擇排序 堆排序 插入排序 直接插入排序 希爾排序 1.氣泡排序演算法的運作如下 從後往前 比較相鄰的元素。如果第乙個比第二個大,就交換他們兩個。對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。針對所有的元...

經典排序演算法C

氣泡排序 依次比較相鄰的兩個元素,如果前者大於後者,則交換順序。第一趟完成後最後的元素是最大的,然後針對所有的元素重複以上的步驟,除了最後乙個。時間複雜度n 2 void bubblesort vector arr 選擇排序 在序列中,找到最小元素,放到序列的起始位置作為已排序序列 然後,再從剩餘未...