在另外的文章中介紹了快速,堆,歸併排序,這三個排序都是高效的排序,下面介紹一些時間複雜度為o(n^2)的排序。
氣泡排序,顧名思義,就是將小的元素往上冒,大的元素往下沉,實際在變成的時候用的是大的元素往下沉的方法。每一趟過後,都有乙個最大的元素被沉到底。下一次排序時陣列規模減少了1。主要應用到了相鄰兩個元素互相比較的方法,是乙個穩定的排序,但是無論陣列是否有序,都要比較n^2次。是屬於蠻力法的乙個應用。**如下:
void sortnamesspace::bubblesort(int *pdata, size_t uilength)
for ( size_t i = 0; i < uilength - 1; ++i)
}}}
(引用guo_guo部落格分析
)其特點如下:
(1)穩定的,即如果有 [...,5,5...]這樣的序列,排完序後,這兩個5的順序一定不會改變,這在一般情況下是沒有意義的,但當 5這個節點不僅僅是乙個數值,是乙個結構體或者類例項,而結構體有附帶資料的時候,這兩個節點的順序往往是有意義的,如果能夠穩定有時候是關鍵的,因為如果不穩定則可能破壞附帶資料的順序結構。
(2)比較次數恆定,總是比較 n²/2次,哪怕資料已經完全有序了
(3)最好的情況下,乙個資料也不用移動,氣泡排序的最好情況是:【資料已經有序】
(4)最壞的情況下,移動 n²/2次資料,氣泡排序的最壞情況是:【資料是逆序的】。
插入排序:把乙個元素插入到乙個已經有序的序列中。插入排序的**頁很簡潔易懂,如下所示:
//插入排序
void sortnamesspace::insertsort(int *pdata, size_t uilength)
int icurrentelenment = 0;
size_t i = 1;
size_t j = 0;
for ( ; i < uilength; ++i)
pdata[j] = icurrentelenment;//最後才將要插入的元素插入到最終位置
}}
(引用guo_guo部落格分析
)其特點如下: (
1)穩定的,這點不多做解釋,參見氣泡排序的說明(2
)最好情況下,只做
n-1次比較,不做任何移動,比如
[ 1, 2, 3, 4, 5 ]
這個序列,演算法
a.檢查
2能否插入1前
==>
不能;b.檢查3
能否插入到2前
==>
不能;...
以此類推,只需做完
n-1
次比較就完成排序,
0次移動資料操作。直接插入排序的最好情況是【資料完全有序】(3
)最壞情況下,做
n²/2
次比較,做
n²/2
次移動資料操作,比如
[ 5, 4, 3, 2, 1 ]
這個序列,
4需要插入到5前,
3需要插入到
4,5前,
...1
需要插入到
2,3,4,5
前,同樣由等差數列求和公式,可得比較次數和移動次數都是
n(n-1)/2,
簡記為n²/2
。直接插入排序的最好情況是【資料完全逆序】(4
)有人說直接插入排序是在序列越有序表現越好,資料越逆序表現越差,其實這種說法是錯誤的。舉個例子說明,序列
a [ 6,1,2,3,4,0 ]
,資料其實已經基本有序,只是
0,6的位置不對,簡單
0,6交換即可得到正確序列,但插入排序會把
1,2,3,4
以此插入到
6前,在把
0插入到
1,2,3,4,6
前,幾乎有
2n次移動操作。可見直接插入排序要想達到高效率,要求的有序不是基本有序,而前半部分完全有序,只有尾部有部分資料無序,例如
[0,1,2,3,4,5,5,6,7,8,9,........,107,99,96,101]
對這樣乙個只有尾部有部分資料無序,且尾部資料不會干擾到序列首部的
[0,1,2,3,4....]
的位置時,直接插入排序
是其他任何演算法都無法匹敵的。
選擇排序:在待排序序列中選擇乙個最小的元素插入到前面的有序序列的後面的位置。**如下:
//選擇排序
void sortnamesspace::selectsort(int *pdata, size_t uilength)
int imin = 0;
size_t i = 0;
size_t j = 0;
size_t iindexminelement = 0;//記錄的最小元素的索引
for ( ; i < uilength - 1; ++i) //需要(n - 1)趟
}swap(pdata[iindexminelement],pdata[i]);
}}
其特點如下:選擇排序是不穩定的演算法,最壞情況是逆序和有大量相同的元素。最好情況是陣列基本有序。
希爾排序時改進版的插入排序,插入排序的增量為0,而希爾排序的增量可以自己設定,插入的位置是由增量算出的位置。**如下:
//希爾排序
void sortnamesspace::shellsort( int *pdata,size_t uilength )
int iincrement = 0;
int icurrentelenment = 0;
size_t i = 0;
size_t j = 0;
for ( iincrement = uilength/2; iincrement > 0; iincrement /= 2)//每次的增量變更
pdata[j] = icurrentelenment;
} }}
(引用
guo_guo部落格分析
)其特點如下:
希爾排序最有趣的地方在於她的步長序列選擇上,步長序列選擇的好壞直接決定了演算法的效率,這也是為什麼希爾排序效率是乙個
n²/2 ~nlog²n
的原因,糾正一下傳說來自《大話資料結構》的表中將希爾排序記作了
n²/2 ~nlogn
,這是不對的,目前的理論研究證明的希爾排序最好效率是
nlog²n
,這個logn
上的平方是不能少的,差距很大的。上面的希爾排序中使用乙個特殊的序列,是
marcin ciura
發布的研究報告中得到的目前已知最好序列,在使用這個特別的步長序列時,希爾排序的效率是
nlog²n
。那麼希爾排序有哪些特點呢? (
1)希爾排序是不穩定的 (
2)希爾排序特別適合於,大部分資料基本有序,只有少量資料無序的情況下,如
[ 6,1,2,3,4,5,0 ]
希爾排序能迅速定位到無序資料,從而迅速完成排序 (
3)希爾排序的步長序列,無論如何選擇最後乙個必須是1,
因為希爾排序的最後一步本質上就是直接插入排序,只是通過前面的步長排序,將序列盡量調整到直接插入排序的最高效狀態;
希爾排序可以理解為特殊的直接插入排序,區別在於步長的選擇上,乙個預設的為
1,乙個是人為設定的。 (
4)研究表明優良的步長序列選擇下,在中小規模資料排序時,希爾排序是可以快過快速排序的。因為希爾排序的最佳步長下效率是
n*logn*logn*a(
非常小常數因子
),而快速排序的效率是
n*logn*b(
小常數因子),在
n小於一定規模時,
logn*a
是可能小於
b的,比如
a=0.25
,b=4
,n = 65535
;此時logn*a<4
,b=4。
綜合上述,得到的各種情況下的最優排序分別是: (
1)序列完全有序,或者序列只有尾部部分無序,且無序資料都是比較大的值時,
【直接插入排序】最佳(哪怕資料量巨大,這種情形下也比其他任何演算法快) (
2)資料基本有序,只有少量的無序資料零散分布在序列中時,【希爾排序】最佳 (
3)資料基本逆序,或者完全逆序時,
【希爾排序】最佳(哪怕是資料量巨大,希爾排序處理逆序數列,始終是最好的,當然三數取中優化的快速排序也工作良好) (
4)資料報含大量重複值,【希爾排序】最佳(來自實驗測試,直接插入排序也表現得很好) (
5)資料量比較大或者巨大,單執行緒排序,且較小幾率出現基本有序和基本逆序時,【快速排序】最佳 (
6)資料量巨大,單執行緒排序,且需要保證最壞情形下也工作良好,【堆排序】最佳 (
7)資料量巨大,可多執行緒排序,不在乎空間複雜度時,【歸併排序】最佳
插入排序 選擇排序 氣泡排序 希爾排序
引入概念 排序穩定性 輸入資料的順序,排序後不能改變。例如,1,2,3,3,5.排序完若第乙個3和第二個3互換,則為不穩定。1.插入排序 穩定 解釋 像打撲克時整理牌時一樣,遇到小牌就插在前面比他大的前面,而後面的牌順次後移 直到處理完最後一張牌。優點 比氣泡排序只能處理相鄰資料更為靈活,適用於資料...
java 氣泡排序 選擇排序 插入排序 希爾排序
最壞均時間複雜度o n 2 整個陣列都是逆序的情況 最好情況o n 整個陣列都已經是順序的情況 對應version3,version1 2不是 public static void main string arg 小到大 version 2 for int i 0 i i j 小到大 version...
排序演算法(氣泡排序,選擇排序,插入排序,希爾排序)
工作原理 1 比較相鄰的元素。如果第乙個比第二個大,就交換它們兩個 2 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對,這樣在最後的元素應該會是最大的數 3 針對所有的元素重複以上的步驟,除了最後乙個 4 重複步驟1 3,直到排序完成。obj 10,4,29,5,7,80,34,19,8...