快排函式引數說明
qsort(s,n,sizeof(s[0]),cmp)
s
需要排序的陣列名n
陣列中元素的個數sizeof()
返回一個元素的 sizecmp
比較函式,具體見下文
比較函式
典型的比較函式定義是
int cmp(const void *a,const void *b)
其中,函式名 cmp 和引數名 a, b 都是可以自定義的,但型別必須是 const void *
型。
函式返回值必須是 int 型,如果需要結尾為升序,則在 a > b
的情況下返回正值,反之返回負值。
例如最常見的對 int 陣列進行排序的比較函式寫法如下:
int cmp(const void *a, const void *b) {
return (*(int *) a - *(int *) b);
}
對於 double 陣列而言,由於兩個 double 型別數不能直接判斷相等,因此我們可以處理為只返回 1 和 -1,或者增加其他判斷語句來返回0的情況,這裡我們簡單的作只返回 -1 和 1 作為例子:
int cmp(const void *a, const void *b) {
return ((*(double *) a - *(double *) b > 0) ? 1 : -1);
}
那麼當需要對二維陣列排序時,可以用如下程式碼實現,也可以直接定義為結構體,推薦後者。本程式碼中,如果第一維值相等,則繼續比較第二維的大小,可以根據實際情況修改。
int cmp(const void *a,const void *b)
{
int *c = (int *)a;
int *d = (int *)b;
if(*c != *d)
return *c - *d;
return *(c+1) - *(d+1);
}
完整示例原始碼
#include <stdio.h>
#include <stdlib.h>
int s[10000], n, i;
int cmp(const void *a, const void *b) {
return (*(int *) a - *(int *) b);
}
int main() {
scanf("%d", &n);
for (i = 0; i < n; i++) scanf("%d", &s[i]);
qsort(s, n, sizeof(s[0]), cmp);
for (i = 0; i < n; i++) printf("%d ", s[i]);
return (0);
}
快排函式實現原始碼
void qsort(int a[], int low, int high) {
if (low >= high) {
return;
}
int first = low;
int last = high;
int key = a[first]; // 用字表的第一個記錄作為樞軸
while (first < last) {
while (first < last && a[last] >= key) {
--last;
}
a[first] = a[last]; // 將比第一個小的移到低端
while (first < last && a[first] <= key) {
++first;
}
a[last] = a[first]; // 將比第一個大的移到高階
}
a[first] = key; // 樞軸記錄到位
qsort(a, low, first - 1);
qsort(a, first + 1, high);
}
快排的不穩定性
-
快排是不穩定的,這個不穩定一個表現在其使用的時間是不確定的,最好情況 (O(n)) 和最
壞情況 (O(n^2)) 差距太大,我們一般說的 O(n·log(n)) 都是指的是其平均時間. -
快排是不穩定的,這個不穩定表現在如果相同的比較元素,可能順序不一樣,假設我們有
這樣一個序列 3, 3, 3 但是這三個3是有區別的,我們標記為 3a, 3b, 3c 快排後的結果不一定就是 3a, 3b, 3c 這樣的排列,所以在某些特定場合我們要用結構體來使其穩定。
關於快排的技巧
-
快排 qsort() 的第三個引數,推薦使用sizeof(s[0]),特別是對結構體,
往往自己定義2 * sizeof(int)
可能會出問題,用sizeof(s[0])
既方便又保險。 -
如果要對陣列進行部分排序,比如對一個 s[n] 的陣列排列其從 s[i] 開始的 m 個元素,只需要
在第一個和第二個引數上進行一些修改,例如qsort(&s[i], m, sizeof(s[i]), cmp)
。