演算法一:氣泡排序
每次比較相鄰兩元素,若錯序則交換,多次遍歷,直至無交換,實質上需要排序k-1趟,每次找到未排序元素中的最大值放在已排序序列最後面,穩定。
void bubble_sort(int array, int n)}}
改進:增加狀態變數flag,若某趟迴圈無交換發生,則停止繼續迴圈時間複雜度分析:最好情況,全部有序,在已改進的基礎上,比較n-1次,故時間複雜度為o(n),最壞情況,逆序排列,則需要比較n(n-1)/2次,交換n(n-1)/2次,時間複雜度為o(n^2)。
缺點:一次迴圈內多次交換
演算法二:簡單選擇排序
進行n-1趟排序,每次尋找未排序所有元素的最小值放在已排序序列的最末端,穩定。
void selection_sort(int array,int n)
}
時間複雜度分析:最好情況,全部有序,需要比較n-1次,最好情況無交換,故時間複雜度為o(n),最壞情況比較(n+2)(n-1)/2次(注意j迴圈中有兩次比較),移動次數為(n+4)(n-1)/2次,時間複雜度為o(n^2),但效能上還是略優於氣泡排序和簡單選擇排序。優勢:在基本有序或者記錄數目較少的時候
缺點:共需n趟排序,效率低,並且每次迴圈只能將資料移動一位
演算法四:希爾排序
如上述演算法三,在記錄數目較少時,直接插入排序有優勢,若記錄數目較多,則可將記錄分割成多個子串行,在每個子串行(記錄數目較少)內直接插入排序。當整個序列基本有序時,再對全體進行一次直接插入排序。選擇乙個增量序列,按照增量序列進行k趟排序,每趟排序將整個待排序的記錄序列分割成為m個子序列分別進行直接插入排序,待整個序列中的記錄「基本有序」時(增量降為1),再對全體記錄進行依次直接插入排序,由於跳躍式移動
不穩定。
void shell_sort(int array, int n)
}
時間複雜度分析:取決於增量序列的選擇,對於上述序列複雜度為o(n^3/2),第乙個突破o(n^2)的演算法演算法五:堆排序
直接選擇排序並沒有把每趟的比較結果記錄下來,導致後一趟的比較中有許多前一趟已經做過了,因而比較次數較多,若能找到本趟迴圈要找的值的同時,對其他記錄進行相應的調整,則會提高整體效率。
大頂堆:每個節點的值都大於或等於左右孩子結點的值的完全二叉樹
小頂堆:每個節點的值都小於或等於左右孩子結點的值的完全二叉樹
將待排序的序列構造成乙個大頂堆,根結點則為最大值,將其與堆陣列末尾元素交換,再將剩餘n-1個序列重新構成乙個大頂堆,如此反覆迴圈,便能得到乙個有序序列。故需解決兩個問題:如何構建堆?輸出堆頂後,如何調整成新的堆?
void heapadjust(int *a, int start, int end)
a[start] = temp;
}void heapsort(int a, int n)
}
時間複雜度分析:時間消耗在初始建堆和重建堆的反覆篩選,從最下層最右邊非端點開始與左右孩子比較,最多兩次比較和互換,因此構建堆為o(n);正式排序時,第i次取堆頂記錄重建堆需要o(logi)的時間(完全二叉樹的某個結點到根結點距離為[logi]+1),並且需要取n-1次,因此重建堆複雜度為o(nlogn),整體時間複雜度為o(nlogn)特點:對原始記錄排序狀態不敏感,跳躍式交換不穩定。由於初始建堆所需比較次數較多,不適合待排序個數較少的情況
演算法六:歸併排序
採用分治思想,對任一串行,分成左右子列,子列內部排序,遞迴實現,然後用指標移動合併兩子列實現歸併操作,穩定。
**實現:
void merge(int array,int temparr, int startindex,int midindex,int endindex)
while (i != midindex + 1) //未排完子列剩餘元素直接送人合併列
temparr[k++] = array[i++];
while (j != endindex + 1)
temparr[k++] = array[j++];
for (i = startindex; i <= endindex; i++) //將合併列放入原序列應有的位置
array[i] = temparr[i];
}void mergesort(intarray,inttemparr, intstartindex,intendindex)
#define cutoff 3
void quicksort(intarray,int left, int right)
//從兩側分別找到錯誤分組的元素
while (array[--j] > pivot) {}
if (i < j) //若i,j尚未交錯
swap(&array[i], &array[j]);
else
break; //當前分組正確
}swap(array[i], array[right - 1]); //把樞紐元放到中間
quicksort(array, left, i - 1);
quicksort(array, i + 1,right);
}else
insertionsort(array + left, right - left + 1);//對於小陣列,插入排序更合適
}
*** 與歸併相比,同樣是遞迴,可是分成的兩個子問題並不一定相等(隱患),但分成兩組是在適當的位置進行且非常有效,故比遞迴更快。
演算法八:基數排序
基數排序用於對多關鍵字域資料(例如:一副撲克牌,大小可以看做乙個關鍵字域,花色也可以看做另乙個關鍵字域)進行排序,每次對資料按一種關鍵字域進行排序,然後將該輪排序結果按該關鍵字的大小順序堆放,依次進行其他關鍵字域的排序,最後實現序列的整體排序。
限制:
基數排序需要一種穩定的排序演算法作為子程式,在這裡使用計數排序。
時間複雜度:
(1)給定n個d位k進製數,使用計數排序(耗時:
(2)給定n個b位k進製數,若b太大,可考慮將b分成r段,這時得到n個b/r位k^r進製數,同樣使用計數排序(耗時:
缺點:
不是原址排序;雖然可以達到線性時間複雜度,但是常數因子較大。
八大排序演算法總結
1.直接插入排序 原理 將陣列分為無序區和有序區兩個區,然後不斷將無序區的第乙個元素按大小順序插入到有序區中去,最終將所有無序區元素都移動到有序區 完成排序。要點 設立哨兵,作為臨時儲存和判斷陣列邊界之用。實現 void insertsort node l,int length l i 1 l 0 ...
八大排序演算法總結
插入排序 1.直接插入排序 原理 將陣列分為無序區和有序區兩個區,然後不斷將無序區的第乙個元素按大小順序插入到有序區中去,最終將所有無序區元素都移動到有序區完成排序。要點 設立哨兵,作為臨時儲存和判斷陣列邊界之用。實現 void insertsort node l,int length int i,...
八大排序演算法總結
插入排序 1.直接插入排序 原理 將陣列分為無序區和有序區兩個區,然後不斷將無序區的第乙個元素按大小順序插入到有序區中去,最終將所有無序區元素都移動到有序區完成排序。要點 設立哨兵,作為臨時儲存和判斷陣列邊界之用。實現 void insertsort node l,int length int i,...