之前一共實現了6種比較常見的排序演算法,分別是:
選擇排序,插入排序,氣泡排序,歸併排序,快速排序,堆排序
效率:
衡量乙個演算法的效率包括空間和時間,有時候還要考慮穩定性。
前3種排序的方法效率較低,實現也比較簡單,適合規模比較小的排序,個人認為適合排序總量在10000以下的隨機數組。
後3種排序的方法效率較高,實現稍微複雜一點,但也還好,適合規模較大的排序。
時間方面,前3種排序的複雜度都是o(n^2),後3種排序的複雜度都是o(n*logn),即呈指數級減少(因為基本思路都是遞迴的方式分治)。當然了,這是平均情況。
空間方面,即是否需要額外的空間,只有歸併排序需要乙個陣列長度相同的空間來儲存排序的結果,即o(n)。快速排序的需要o(
log2n
)。其餘排序都不需要額外的空間。
穩定性方面,只有插入排序和歸併排序是穩定的。穩定性保證的是陣列中值相等的資料在排序時順序不變,這在純int型陣列時沒什麼意義,但如果是複雜資料結構的排序,如果改變了順序則可能影響資料結構中其他欄位的排序。
疑問:誰能告訴我為什麼快速排序的空間複雜度是o(
log2n)?
特點:
每種排序都有自己的特點,要不然也不會留傳了這麼久。以下是個人看法:
氣泡排序:比較sb,只適合教學,效率低,但易實現。但能保證穩定。
選擇排序:比氣泡排序好一點,好的地方是交換次數少了,但仍然很sb。而且不穩定。
插入排序:有點像打撲克牌時的排序,但插入時會讓陣列的移動變多,如果是鍊錶則效率很高。且能保證穩定。
歸併排序:典型地遞迴分治,缺點是需要額外的空間來儲存結果。但能保證穩定。
快速排序:跟歸併排序很像,但區別是歸併排序切分的中點是陣列索引,快速排序切分的中點是第乙個資料的值。相同的是,都要碰運氣。但不穩定。
堆排序:思路很特別,花了好幾個班車上的時間片,另外用了撲克牌演示每一步的過程才弄明白流程。但不穩定。
執行時間比較:
這裡就專門寫個測試程式來測試一下這6種排序演算法的執行時間倒底區別有多大。
隨機生成100,000個數:
const int n = 200000;
int o = 0;
int* genrandom()
return a;
}
systemtime starttime = ;
filetime startfiletime = ;
systemtime endtime= ;
filetime sendfiletime= ;
int _tmain(int argc, _tchar* argv)
依次得到的結果如下:
bubblesort:1分37秒818,是的,你沒看錯。。
selectionsort:12秒338。
insertsort:1分11秒23。
mergesort:1秒598
quicksort:0秒036
heapsort:0秒081
說多了都是淚....這才是100,000個數,假設要是千萬級的,差別就更大了,可能冒泡需要幾個小時。。而快速和堆排序都表現的相當優秀。
這也難怪快速排序叫做快速排序。
實現**:
以防我的**實現的有問題,影響了測試效果,特將**列與此,如果有不足之處請各位指教和指正:
//#include "stdafx.h"
#include "windows.h"
#include "time.h"
const int n = 100000;
int o = 0;
int* genrandom()
return a;
}void swap(int& a, int& b)
//small -> large
void selectionsort(int* ua)
o++;
} swap(ua[i], ua[nminindex] ); }}
//small -> large
void insertsort(int* ua)
} }
}//small -> large
void bubblesort(int* ua)
*/for (int j = 0; j < (n-i-1); j++)
o++;
} }
} void merge(int* ua, int nstart, int nmid, int nend)
for (int k = nstart; k <= nend; k++)
else if(j > nend)
else if( a[j] < a[i])
else
/*printf("round %d \r\n", k);
for (int k = nstart; k < nend; k++)
*/ }}
//small -> large
void mergesort(int* ua, int nstart, int nend)
int nmid = nstart + (nend - nstart) / 2;
mergesort(ua, nstart, nmid);
mergesort(ua, nmid+1, nend);
merge(ua, nstart, nmid, nend);
}int quickpartition(int* ua, int nstart, int nend)
} //找到右邊小於中點的值,記錄索引
while( ua[--j] > nflagvalue )
}//兩邊向中間靠攏的過程中相遇則退出
if( i >= j)
//交換兩邊的值
swap( ua[i], ua[j] );
} //將右邊最後乙個小於中點值的數與中點值交換位置,
//保證中點值的左邊都小於中點值,右邊都大於中點值
swap( ua[nstart], ua[j] );
//返回將右邊最後乙個小於中點值的數的索引,做為右邊部分的中點值。
return j;
}void quicksort(int* ua, int nstart, int nend)
int nmid = quickpartition(ua, nstart, nend);
quicksort(ua, nstart, nmid-1);
quicksort(ua, nmid+1, nend);
}void heapadjust(int* ua, int nstart, int nend)
} //如果父結點大於子節點,則退出,否則交換
if (ua[nstart] > ua[nmaxindex])
else
} /*for (int i = 0; i < n; i++)
printf("\r\n");*/
//printf("%d ", o++);
}void heapsort(int* ua, int nstart, int nend)
for (int i = nend-1; i > 0; i--) }
systemtime starttime = ;
filetime startfiletime = ;
systemtime endtime= ;
filetime sendfiletime= ;
int _tmain(int argc, _tchar* argv)
排序演算法的比較與總結
歸併 穩定,o nlogn 遞迴實現 大類排序方法 時間複雜度 空間複雜度 穩定性實現方法 備註交換法 冒泡法最差 平均都是o n 2 最好是o n 1穩定 n較小時較好 交換法雞尾酒冒泡法 最差 平均都是o n 2 最好是o n 1穩定 n較小時較好 交換法快速排序 平均o nlogn 最壞是o ...
氣泡排序改進與總結
5 改進的氣泡排序 從小到大排序 void bubblesort int array int n if 0 exchange return 如果某遍沒有交換,說明已經排序好。6 氣泡排序的穩定性 如果將array j 7 陣列的初始順序對冒泡的影響 如果初始陣列就是從小到大的順序,則氣泡排序的比較次...
快速排序 優化與總結
基礎快排 快排的基本框架就是下邊這樣。更魯棒一點的話,還需要考慮傳入的array是否是非法引數。此處優化 應當將陣列,打亂順序,如果陣列基本有序,快排的時間複雜度將退化到 應該在傳入sort之前就將陣列 shuffle。public static void sort int array,int lo...