排序算法幾種分類方式:
1,穩(wěn)定排序和不穩(wěn)定排序
? ? ? 如果a==b, 當排序之前a在b的前面,排序后,a仍然在b的前面,則該排序算法為穩(wěn)定排序算法。否則為不穩(wěn)定排序算法。
2,非線性時間比較類排序和線性時間非比較類排序算法
? ? ? 非線性時間比較類排序:通過比較來決定元素間的相對位置,由于比較次數(shù),使其時間復雜度不能突破O(nlogn)。
? ? ? 線性時間非比較類排序:不通過比較來決定元素間的相對位置,它可以突破比較排序的時間下限,以線性時間運行。
幾種常見的排序算法介紹:
1,選擇排序
算法原理:依次在元素間比較,從集合中找出最小的元素,放到集合最前面,再從剩下的集合中找出次小的元素,再放到當前集合最前面;依次循環(huán),把所有的元素排好序。
平均時間復雜度O(n*n),空間復雜度O(1)。
選擇排序是不穩(wěn)定排序。
Java代碼?
//?選擇排序:??
public?int[]?selectSort(int[]?nums)?{??
long?start?=?System.currentTimeMillis();??
for?(int?i?=?0;?i?<?nums.length;?i++)?{??
int?minIndex?=?i;??
for?(int?j?=?i?+?1;?j?<?nums.length;?j++)?{??
if?(nums[j]?<?nums[minIndex])?{??
????????????????????minIndex?=?j;??
????????????????}??
????????????}??
????????????swap(nums,?i,?minIndex);??
????????}??
System.out.println("Select?Sort,?count?time?=?"?+?(System.currentTimeMillis()?-?start)?+?"ms");??
return?nums;??
????}??
private?void?swap(int[]?nums,?int?x,?int?y)?{??
if?(x?==?y)??
return;??
int?temp?=?nums[x];??
????????nums[x]?=?nums[y];??
????????nums[y]?=?temp;??
????}??
2,快速排序
算法原理:從元素集合中挑選出一個基準(Pivot),一次遍歷之后,把所有大于基準的元素放在基準值的右邊,所有小于基準的元素放在基準值的左邊。然后遞歸分別對左邊和右邊執(zhí)行同樣的操作。
遍歷過程如下:首先選定基準,然后分別從左邊和右邊開始遍歷,直至左右相遇則遍歷完成。左邊開始往右邊遍歷時,遇到比基準值大的元素,則停下來,右邊開始往左邊遍歷時,遇到比基準值小的元素,則停下來,然后把左右兩個元素交換。然后繼續(xù)遍歷,直至相遇。
注意:如果選定的基準是左邊第一個元素,則先從右邊開始往左遍歷,這樣能保證停下來時的元素是不大于基準的元素。反之,則從左邊開始遍歷。
平均時間復雜度O(nlogn),空間復雜度O(logn)。
快速排序是不穩(wěn)定排序
Java代碼?
//?快速排序:??
public?int[]?quickSort(int[]?nums)?{??
long?start?=?System.currentTimeMillis();??
if?(nums?==?null?||?nums.length?==?0)??
return?nums;??
quickSortByPivot(nums,0,?nums.length?-?1);??
System.out.println("Quick?Sort,?count?time?=?"?+?(System.currentTimeMillis()?-?start)?+?"ms");??
return?nums;??
????}??
private?void?quickSortByPivot(int[]?nums,?int?left,?int?right)?{??
int?l?=?left,?r?=?right;??
int?pivot?=?nums[left];??
while?(l?<?r)?{??
while?(r?>?l?&&?nums[r]?>=?pivot)??
????????????????r--;??
while?(r?>?l?&&?nums[l]?<=?pivot)??
????????????????l++;??
if?(l?<?r)??
????????????????swap(nums,?l,?r);??
????????}??
????????swap(nums,?left,?l);??
if?(l?-?1?>?left)??
quickSortByPivot(nums,?left,?l?-1);??
if?(right?>?l?+?1)??
quickSortByPivot(nums,?l?+1,?right);??
????}??
3,簡單插入排序
算法原理:把當前元素插入到已排好序的元素集合的對應位置。把第一個元素當成已經(jīng)排好序的元素,從第二個元素(新元素)開始,從排好序的元素(待比較元素)中后向前逐一掃描比較,如果待比較的元素比新元素大,則把新元素與待比較元素交換,然后新元素繼續(xù)往前比較,直至結束。當每個元素都與排好序的元素完成比較,則排序完成。
平均時間復雜度O(n*n),空間復雜度O(1)。
簡單插入排序是穩(wěn)定排序
Java代碼?
//?簡單插入排序:??
public?int[]?simpleInsertSort(int[]?nums)?{??
long?start?=?System.currentTimeMillis();??
for?(int?i?=?1;?i?<?nums.length;?i++)?{??
int?pre?=?i?-?1,?cur?=?i;??
while?(pre?>=?0?&&?nums[pre]?>?nums[cur])?{??
????????????????swap(nums,?pre,?cur);??
????????????????cur?=?pre;??
????????????????pre--;??
????????????}??
????????}??
System.out.println("Simple?Insert?Sort,count?time?=?"?+?(System.currentTimeMillis()?-?start)?+?"ms");??
return?nums;??
????}??
4,希爾(shell)排序(縮小增量排序)
算法原理:是插入排序的改進版,考慮到插入排序時,有可能某個元素需要插入到比較遠的位置,導致不斷的重復插入。因此希爾排序會優(yōu)先比較距離較遠的元素。希爾排序引入步長概念,先選定一個步長(可根據(jù)集合大小確定),然后使用插入排序思想比較相隔步長距離的各個元素。然后把步長減一,繼續(xù)比較,直至步長為1,此時相當于插入排序,但是目前的集合已經(jīng)近似有序了。
平均時間復雜度O(n^1.3),空間復雜度O(1)。
希爾排序是不穩(wěn)定排序。
Java代碼?
//?希爾排序?,??
public?int[]?shellSort(int[]?nums)?{??
long?start?=?System.currentTimeMillis();??
if?(nums?==?null?||?nums.length?==?0)??
return?null;??
int?gap?=?nums.length?/?3;//?步長??
while?(gap?>?0)?{??
for?(int?k?=?0;?k?<?gap;?k++)?{??
int?cur?=?k;??
int?pre?=?k;??
while?(cur?<?nums.length)?{??
if?(nums[cur]?<?nums[pre])?{??
????????????????????????swap(nums,?cur,?pre);??
????????????????????}??
????????????????????pre?=?cur;??
????????????????????cur?+=?gap;??
????????????????}??
????????????}??
????????????gap--;??
????????}??
System.out.println("Shell?Sort,count?time?=?"?+?(System.currentTimeMillis()?-?start)?+?"ms");??
return?nums;??
????}??
5,冒泡排序
算法原理:每次遍歷一次集合,比較相鄰元素,把較大的元素移到后面,完成一次遍歷時,則最大的元素已經(jīng)移到最后,然后繼續(xù)遍歷剩下的無序集合,把當前集合最大的移到最后面。經(jīng)歷n次遍歷后,完成排序。
冒泡排序還可以稍微改進,當排序過程中,發(fā)現(xiàn)待排序集合已經(jīng)是有序的,則可以不需要進一步遍歷了。
平均時間復雜度O(n*n),空間復雜度O(1)。
冒泡排序是穩(wěn)定排序。
Java代碼?
//?冒泡排序:??
public?int[]?bubbleSort(int[]?nums)?{??
long?start?=?System.currentTimeMillis();??
if?(nums?==?null?||?nums.length?==?0)??
return?null;??
for?(int?i?=?0;?i?<?nums.length;?i++)?{??
boolean?isSorted?=?true;//?假設當前已經(jīng)有序,冒泡排序改進,如果當前循環(huán)發(fā)現(xiàn)已經(jīng)有序,則不需要繼續(xù)遍歷。??
for?(int?j?=?1;?j?<?nums.length?-?i;?j++)?{??
if?(nums[j]?<?nums[j?-?1])?{??
swap(nums,?j,?j?-1);//?一次遍歷后,如果有交換動作,則不是有序的.??
isSorted?=false;??
????????????????}??
????????????}??
System.out.println("bubble?Sort?current?index:"?+?i);??
if?(isSorted)??
return?nums;??
????????}??
System.out.println("Bubble?Sort,count?time?=?"?+?(System.currentTimeMillis()?-?start)?+?"ms");??
return?nums;??
????}??
6,堆排序
算法原理:堆排序是利用堆這種數(shù)據(jù)結構來設計的排序算法。堆可以看做一個近似完全二叉樹的結構。堆分為大頂堆和小頂堆。大頂堆滿足如下性質,父節(jié)點的值總是大于(等于)子節(jié)點的值,小頂堆滿足如下性質,父節(jié)點的值總是小于(等于)子節(jié)點的值。
從0開始對堆中的節(jié)點進行編號,則其節(jié)點和其父節(jié)點以及子節(jié)點的編號關系如下,當前節(jié)點編號為i:
父節(jié)點編號 parent(i) = i / 2;
左子節(jié)點編號 left(i) = 2 * i + 1;
右子節(jié)點編號 right(i) = 2 * i + 2;
堆排序過程為首先根據(jù)集合元素大小建立一個大頂堆,當前的堆是無序的,然后對每個元素進行調整,使其符合大頂堆的規(guī)則,當前節(jié)點值大于等于子節(jié)點值。完成一次堆的調整后,堆的第一個元素,即堆頂元素,則為集合中的最大元素。此時堆頂元素為有序元素,把它與集合中的最后一個位置的元素互換,然后繼續(xù)為剩下的其他元素創(chuàng)建大頂堆。直至最后,所有的元素都為有序元素。
平均時間復雜度O(nlogn),空間復雜度O(1)。
堆排序是不穩(wěn)定排序。
Java代碼?
//?最大堆排序:??
public?int[]?heapSort(int[]?nums)?{??
long?start?=?System.currentTimeMillis();??
if?(nums?==?null?||?nums.length?==?0)??
return?null;??
????????buildMaxHeap(nums);??
System.out.println("Heap?Sort,count?time?=?"?+?(System.currentTimeMillis()?-?start)?+?"ms");??
return?nums;??
????}??
private?void?adjustHeapOfIndex(int[]?nums,?int?index,?int?heapSize)?{??
//?System.out.println("index|heapSize:"?+?index?+?"|"?+?heapSize);??
int?left?=?index?*?2?+?1;??
int?right?=?index?*?2?+?2;??
int?largest?=?index;??
if?(left?<?heapSize?&&?nums[left]?>?nums[largest])??
????????????largest?=?left;??
if?(right?<?heapSize?&&?nums[right]?>?nums[largest])??
????????????largest?=?right;??
if?(index?!=?largest)?{??
????????????swap(nums,?index,?largest);??
????????????adjustHeapOfIndex(nums,?largest,?heapSize);??
????????}??
//?this.printArrays("adjust?heap",?nums);??
????}??
private?int[]?buildMaxHeap(int[]?nums)?{??
int?heapSize?=?nums.length;??
while?(heapSize?>?0)?{//?從nums.length到1,不斷構建最大堆;??
//?構建最大堆;??
for?(int?i?=?heapSize?-?1;?i?>=?0;?i--)?{?//?針對每個index,不斷調整堆;??
????????????????adjustHeapOfIndex(nums,?i,?heapSize);??
????????????}??
//?this.printArrays("build?max?heap:",nums);??
swap(nums,0,?heapSize?-?1);?//?堆構建完成后?最大的值為nums[0],完后交換放到最后??
????????????heapSize--;??
????????}??
return?nums;??
????}??
7,歸并排序
?算法原理:歸并排序主要是采用分治法,把兩個已排好序的子集合合并成一個有序的集合。子集的排序則是采用遞歸方法,如果子集只包含一個元素,則為一個有序的集合。
平均時間復雜度O(nlogn),空間復雜度O(n)。
歸并排序是穩(wěn)定排序。
Java代碼?
//?歸并排序??
public?int[]?mergeSort(int[]?nums)?{??
long?start?=?System.currentTimeMillis();??
if?(nums?==?null?||?nums.length?==?0)??
return?null;??
//?System.out.println("start?to?merge?sort:");??
int[]?temp?=?new?int[nums.length];??
mergeSort(nums,0,?nums.length?-?1,?temp);??
System.out.println("Merge?Sort,count?time?=?"?+?(System.currentTimeMillis()?-?start)?+?"ms");??
return?nums;??
????}??
public?void?mergeSort(int[]?nums,?int?start,?int?end,?int[]?temp)?{??
if?(end?-?start?>?0)?{??
int?sublength?=?(end?-?start)?/?2;??
mergeSort(nums,?start,?start?+?sublength,?temp);//?分別把兩個子串排好序?即一直劃分到只剩一個元素,則就是一個排好序的子串。??
mergeSort(nums,?start?+?sublength?+1,?end,?temp);??
//?System.out.println("Merge?Sort:"?+?start?+?"|"?+?sublength?+?"|"?+?end);??
mergeArrays(nums,?start,?start?+?sublength,?start?+?sublength?+1,?end,?temp);//?把兩個排好序的子串合并??
????????}??
????}??
private?int[]?mergeArrays(int[]?nums,?int?lstart,?int?lend,?int?rstart,?int?rend,?int[]?temp)?{??
if?((lend?-?lstart)?<?0?&&?(rend?-?rstart)?<?0)??
return?nums;??
int?tempindex?=?lstart;??
int?leftindex?=?lstart,?rightindex?=?rstart;??
//?System.out.println("tempindex|leftindex?"?+?tempindex?+?"|"?+?leftindex);??
while?(leftindex?<=?lend?&&?rightindex?<=?rend)?{??
if?(nums[leftindex]?<=?nums[rightindex])?{??
????????????????temp[tempindex++]?=?nums[leftindex++];??
}else?{??
????????????????temp[tempindex++]?=?nums[rightindex++];??
????????????}??
????????}??
while?(leftindex?<=?lend)?{??
????????????temp[tempindex++]?=?nums[leftindex++];??
????????}??
while?(rightindex?<=?rend)?{??
????????????temp[tempindex++]?=?nums[rightindex++];??
????????}??
//?System.out.println("fininsh?index?"?+?tempindex?+?"|"?+?leftindex);??
for?(int?k?=?lstart;?k?<=?rend;?k++)?{//?把經(jīng)過處理的數(shù)組里的值全部更新到原數(shù)組中??
????????????nums[k]?=?temp[k];??
????????}??
//?this.printArrays("Merge?Arrays:",?nums);??
return?nums;??
????}??
8,基數(shù)排序
算法原理:基數(shù)排序是把待排序的數(shù)字分為低位和高位,低位先排序,然后收集,再按高位排序,再收集,直至最高位,則排序完成。注意基數(shù)排序無法處理負數(shù)。
排序過程為,首先得到集合中的最大數(shù),根據(jù)最大數(shù),得到需要按位循環(huán)排序的次數(shù)。
在每次按位排序時,先初始化10個桶,分別存放余數(shù)為0-9的元素個數(shù),在一次遍歷之后,10個桶中已保存各個余數(shù)出現(xiàn)的次數(shù),然后再根據(jù)余數(shù)個數(shù)更新10個桶中的相應元素應該存放的位置,比如余數(shù)為1的元素會排在余數(shù)為0的元素的后面,因此如果余數(shù)為0的元素個數(shù)為5,則余數(shù)為1的元素至少會在第5個位置之后,由此統(tǒng)計元素應該在集合中出現(xiàn)的位置。
之后再次從大到小遍歷整個集合,根據(jù)元素的余數(shù),得到對應桶的值,即為該元素在新的集合中的下標值,存放好一個元素,就把對應桶中的值相應減一。遍歷結束,則這次按位排序結束,得到一個按低位排序的集合。
再取較高位,進行排序。直至按最高位排序結束,則此時得到的集合就是一個有序的集合。
平均時間復雜度O(2n*k),k為按位排序的次數(shù);空間復雜度O(n+k),k為桶的數(shù)量;數(shù)據(jù)量大的話,k會遠遠小于n。?
基數(shù)排序是穩(wěn)定排序。
Java代碼?
//?基數(shù)排序?基數(shù)排序不能處理負數(shù);??
public?int[]?radixSort(int[]?nums)?{??
long?start?=?System.currentTimeMillis();??
if?(nums?==?null?||?nums.length?==?0)??
return?null;??
int?max?=?nums[0];??
for?(int?cur?:?nums)?{//?先得到最大數(shù)??
if?(cur?>?max)??
????????????????max?=?cur;??
????????}??
int[]?temp?=?new?int[nums.length];??
int?exp?=?1;??
do?{??
int[]?buckets?=?new?int[10];//?針對余數(shù)的桶?統(tǒng)計余數(shù)個數(shù)??
for?(int?j?=?0;?j?<?nums.length;?j++)?{??
buckets[(nums[j]?/?exp)?%10]++;//?保存每個余數(shù)出現(xiàn)的個數(shù)??
????????????}??
//?this.printArrays("buckets?nums?of?exp:"?+?exp,?buckets);??
for?(int?l?=?1;?l?<?10;?l++)?{??
buckets[l]?+=?buckets[l?-1];//?統(tǒng)計余數(shù)對應的數(shù)按順序出現(xiàn)在整個數(shù)組中的位置?即余數(shù)越小?則其在數(shù)組中排在越前面??
????????????}??
//?this.printArrays("buckets:",?buckets);??
//?this.printArrays("before?bucket:",?nums);??
//?從數(shù)組最后往前循環(huán)?因為buckets中數(shù)據(jù)的位置從大到小遞減.??
for?(int?m?=?nums.length?-?1;?m?>=?0;?m--)?{??
//?System.out.println("m,?value:"?+?m?+?"|"?+?nums[m]?+?"|"?+??
//?buckets[(nums[m]/exp)%10]);??
//?this.printArrays("nums:",?nums);??
temp[buckets[(nums[m]?/?exp)?%10]?-?1]?=?nums[m];//?每存儲一個數(shù)據(jù)后,則把buckets中對應的數(shù)據(jù)減一;??
buckets[(nums[m]?/?exp)?%10]--;??
//?this.printArrays("buckets:",?buckets);??
????????????}??
for?(int?k?=?0;?k?<?nums.length;?k++)?{//?更新值??
????????????????nums[k]?=?temp[k];??
????????????}??
//?this.printArrays("After?bucket:"?+?exp,?temp);??
exp?*=10;??
}while?(max?/?exp?>?0);??
System.out.println("Radix?Sort,count?time?=?"?+?(System.currentTimeMillis()?-?start)?+?"ms");??
return?nums;??
????}??
9,計數(shù)排序
算法原理:計數(shù)排序不是基于比較,而是將待排序的數(shù)據(jù)轉換為鍵存儲在額外開辟的數(shù)組空間中。作為一種線性時間復雜度的排序,計數(shù)排序要求待排序的數(shù)據(jù)必須是有確定范圍的整數(shù)。
排序過程為,先得到待排序數(shù)據(jù)中的最大值和最小值,然后根據(jù)最大值和最小值開辟一個新的數(shù)組空間,然后遍歷整個數(shù)據(jù)集合,統(tǒng)計各個元素出現(xiàn)的次數(shù),并且存入與元素值對應的數(shù)組下標。
然后對數(shù)組中的計數(shù)進行統(tǒng)計,計算出每個元素應該存放的位置,最后反向遍歷數(shù)據(jù)集合,根據(jù)每個元素值,在數(shù)組中獲取元素應該存放的位置。
平均時間復雜度O(n+k),空間復雜度(n+k)。k為數(shù)據(jù)集合中最大值和最小值的范圍。如果待排序集合數(shù)據(jù)比較集中,計算排序是一個很有效的排序算法。
計算排序是穩(wěn)定排序。
Java代碼?
//?計數(shù)排序??
public?int[]?countingSort(int[]?nums)?{??
long?start?=?System.currentTimeMillis();??
if?(nums?==?null?||?nums.length?==?0)??
return?null;??
//?先得到待排序數(shù)據(jù)的范圍??
int?min?=?nums[0],?max?=?nums[0];??
for?(int?curvalue?:?nums)?{??
if?(curvalue?<?min)??
????????????????min?=?curvalue;??
if?(curvalue?>?max)??
????????????????max?=?curvalue;??
????????}??
//?根據(jù)數(shù)據(jù)范圍初始化數(shù)組?進行計數(shù)??
int[]?counts?=?new?int[max?-?min?+?1];??
//?遍歷數(shù)組?進行計數(shù)??
for?(int?k?:?nums)?{??
????????????counts[k?-?min]++;??
????????}??
//?更新數(shù)組中各元素的位置??
for?(int?k?=?1;?k?<?counts.length;?k++)?{??
counts[k]?+=?counts[k?-1];??
????????}??
this.printArrays("Counting?arr:",?counts);??
int[]?temp?=?new?int[nums.length];??
for?(int?i?=?nums.length?-?1;?i?>=?0;?i--)?{??
//?System.out.println("counts?index:"?+?(nums[i]-min)?+?",count?value:"?+??
//?counts[nums[i]-min]);??
temp[counts[nums[i]?-?min]?-1]?=?nums[i];??
????????????counts[nums[i]?-?min]--;??
????????}??
for?(int?j?=?0;?j?<?nums.length;?j++)?{//?更新值??
????????????nums[j]?=?temp[j];??
????????}??
System.out.println("Counting?Sort,count?time?=?"?+?(System.currentTimeMillis()?-?start)?+?"ms");??
return?nums;??
????}??
10,桶排序
算法原理:桶排序是計數(shù)排序的升級版,利用函數(shù)的映射關系,把數(shù)據(jù)映射到有限的桶中,然后對每個桶進行單獨排序,可使用快速排序等其他算法。最后把幾個桶的元素合并,完成排序。
桶排序的時間復雜度取決于各個桶的排序算法,其他部分的時間復雜度為O(n)。顯然,桶劃分得越多,各個桶中的數(shù)據(jù)越少,每個桶的排序時間越少,效率越高,但相應的,空間消耗也越大。
平均時間復雜度O(n+k),空間復雜度O(n+k)。
Java代碼?
//?桶排序算法??
public?int[]?bucketSort(int[]?nums)?{??
long?start?=?System.currentTimeMillis();??
if?(nums?==?null?||?nums.length?==?0)??
return?null;??
if?(nums.length?<=?1)??
return?nums;??
//this.printArrays("bucket?sort:",?nums);??
//?先得到待排序數(shù)據(jù)的范圍??
int?min?=?nums[0],?max?=?nums[0];??
for?(int?curvalue?:?nums)?{??
if?(curvalue?<?min)??
????????????????min?=?curvalue;??
if?(curvalue?>?max)??
????????????????max?=?curvalue;??
????????}??
//?根據(jù)數(shù)的范圍?確定桶的個數(shù)?以及桶的映射函數(shù)??
//?在此假設最多分十個桶?然后把數(shù)據(jù)分別放入對應桶內??
//?每個桶使用List??
int?bucketNum?=?10;??
int?step?=?0;??
if?((max?-?min)?<?10)??
bucketNum?=?max?-?min?+1;??
step?=?(max?-?min?+1)?/?bucketNum;//?根據(jù)bucketNum和step分出bucketNum個桶,范圍?[min,min+step),最后一個桶還包含剩下的余數(shù);??
//?初始化桶??
List[]?buckets?=new?ArrayList[bucketNum];??
for?(int?bk?=?0;?bk?<?buckets.length;?bk++)?{??
buckets[bk]?=new?ArrayList();??
????????}??
System.out.println("Bucketnum:"?+?bucketNum);??
//?遍歷數(shù)組?把元素分別放入桶中??
for?(int?curnum?:?nums)?{??
int?curindex?=?(curnum?-?min)?/?step;??
if?(curindex?>?buckets.length?-?1)??
curindex?=?buckets.length?-1;??
System.out.println("curnum:"?+?curnum?+?",curindex?=?"?+?curindex?+?",min?=?"?+?min?+?",step?=?"?+?step);??
????????????buckets[curindex].add(curnum);??
????????}??
//?分別對各個桶進行排序?并且把每個桶中各元素合并??
int?index?=?0;??
for?(List?list?:?buckets)?{??
int[]?temp?=?new?int[list.size()];??
for?(int?k?=?0;?k?<?list.size();?k++)?{??
????????????????temp[k]?=?(Integer)?list.get(k);??
????????????}??
int[]?tempresult?=?bucketSort(temp);??
if?(tempresult?!=?null)??
for?(int?value?:?tempresult)??
????????????????????nums[index++]?=?value;??
????????}??
System.out.println("Bucket?Sort,count?time?=?"?+?(System.currentTimeMillis()?-?start)?+?"ms");??
return?nums;??
????}??
排序算法總結:
1,如果待排序的集合規(guī)模較小,如n<50,可用簡單插入排序或者選擇排序。
2,如果待排序的集合基本有序,可用簡單插入排序或者冒泡排序。
3,如果待排序的集合規(guī)模較大,則應采用時間復雜度O(nlogn)的排序方法,如快速排序,堆排序或歸并排序。
? ? ?當待排序的元素是隨機分布的,快速排序是平均時間最短的;
? ? ?堆排序雖然時間復雜度跟快速排序一樣,但是實際上的時間消耗(建堆,調整堆)會比快速排序多,因此一般選擇快速排序。
? ? ?但是相比快速排序,堆排序的空間的優(yōu)點是占用更少,也不像快速排序,會出現(xiàn)最壞的情況。
? ? ?如果需要穩(wěn)定的排序算法,則可選歸并排序。
4,堆排序適用于在一個集合n中,快速找出前m個元素(m<n),每次建堆,調整堆,都找出一個元素,執(zhí)行m次則找出前m個元素。
5,如果待排序的數(shù)據(jù)比較集中。則可以采用計數(shù)排序。
6,實際算法使用時,可以多個算法一起使用,以達到更好的效果。如歸并排序中,桶排序中,對子串的處理都可以選擇其他效率更好的算法。
每個算法代碼可見:https://github.com/yangwu/JavaDemo