排序:假設含有n個記錄的序列爲{r1, r2, ……, rn},其相應的關鍵字分別爲{k1, k2, ……, kn},需確定1,2,……, n的一種排列p1, p2……, pn,使其相應的關鍵字滿足kp1<=kp2……<=kpn非遞減(非遞增)關係,即使得序列成爲一個關鍵字有序的序列{rp1, rp2, ……, rpn},這樣的操作就稱爲排序。
多個關鍵字排序最終都可以轉化爲單個關鍵字的排序。下面討論的是單個關鍵字的排序。
排序的穩定性:假設ki=kj(1<=i<=n, 1<=j<=n, i != j),且在排序前的序列中ri領先於rj(即i<j)。如果排序後ri仍領先於rj,則稱所用的排序方法是穩定的;反之,若可能使得排序後的序列中rj領先於ri,則稱所用的排序方法是不穩定的。
內排序與外排序:
內排序是在排序整個過程中,待排序的所有記錄全部被放置在內存中。
外排序是由於排序的記錄個數太多,不能同時放置在內存,整個排序過程需要在內外存知己多次交換數據才能進行。
排序算法的性能主要受3個方面的影響:時間性能,輔助空間,算法的複雜性。
根據排序過程中藉助的主要操作,內排序分爲:
插入排序:直接插入排序、希爾排序
交換排序:冒泡排序、快速排序
選擇排序:簡單選擇排序、堆排序
歸併排序
按照算法的複雜度分爲兩大類,冒泡排序,簡單選擇排序和直接插入排序屬於簡單算法,,而希爾排序,堆排序,歸併排序,快速排序屬於改進算法。
排序用到的結構和函數:
先提供一個用於排序的順序表結構:
#define MAXSIZE 10 //用於要排序數組個數最大值,可根據需要修改
typedef struct
{
int r[MAXSIZE + 1]; //用於存儲要排序數組,r[0]用作哨兵或臨時變量
int length; //用於記錄順序表的長度
} SqList;
由於排序最最常用的操作就是數組兩元素的交換:
//交換L中數組r的下標爲i和j的值
void swap(SqList *L, int i, int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
7種算法的對比
排序方法 | 平均情況 | 最好情況 | 最壞情況 | 輔助空間 | 穩定性 |
冒泡排序 | O(nxn) | O(n) | O(nxn) | O(1) | 穩定 |
簡單選擇排序 | O(nxn) | O(nxn) | O(nxn) | O(1) | 穩定 |
直接插入排序 | O(nxn) | O(n) | O(nxn) | O(1) | 穩定 |
希爾排序 | O(nlogn)~O(nxn) | O(n1.3) | O(nxn) | O(1) | 不穩定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不穩定 |
歸併排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 穩定 |
快速排序 | O(nlogn) | O(nlogn) | O(nxn) | O(logn)~O(n) | 不穩定 |