經典排序之快排及其優化
阿新 • • 發佈:2019-01-12
基礎快排:
int __partition(int arr[], int l, int r) { int v = arr[l]; int j = l ; for (int i = l + 1; i <= r; i++) { if (arr[i] < v){ swap(arr[i], arr[j + 1]); j++; } } swap(arr[l], arr[j]); return j; } void __quickSort(int arr[], int l, int r) { if (l >= r) return; int p = __partition(arr, l, r); __quickSort(arr, l, p - 1); __quickSort(arr, p + 1, r); } void quickSort(int arr[], int n) { __quickSort(arr, 0, n - 1); }
優化快排:
基礎快排的缺點:
- 如果陣列為有序陣列,時間複雜度退化到O(n^2)
- 如果陣列中存在大量重複元素,時間複雜度也會退化到O(n^2),如圖
解決方法:1.隨機選取中軸元素;2.使用前後兩指標同時進行partition;
int __partition2(int arr[], int l, int r) { swap(arr[l], arr[rand() % (r - l + 1) + l]); int v = arr[l]; int i = l + 1; int j = r; while (true) { while (i <= r && arr[i] < v) i++; while (j >= l + 1 && arr[j] > v) j--; if (i > j) break; swap(arr[i++], arr[j--]); } swap(arr[j], arr[l]); return j; } void __quickSort(int arr[], int l, int r) { if (l >= r) return; int p = __partition2(arr, l, r); __quickSort(arr, l, p - 1); __quickSort(arr, p + 1, r); } void quickSort(int arr[], int n) { srand(time(NULL)); __quickSort(arr, 0, n - 1); }
三路快排:
優點:針對大量重複元素的情況,工業界常用。
void __quickSort3Ways(int arr[], int l, int r) { if (l >=r ) { return; } swap(arr[l], arr[rand() % (r - l + 1) + l]); int v = arr[l]; int lt = l; // arr[l+1...lt] < v int gt = r + 1; // arr[gt...r] > v int i = l + 1; // arr[lt+1...i) == v while (i < gt) { if (arr[i] < v) { swap(arr[i], arr[lt + 1]); i++; lt++; } else if (arr[i] > v) { swap(arr[i], arr[gt - 1]); gt--; } else { // arr[i] == v i++; } } swap(arr[l], arr[lt--]); __quickSort3Ways(arr, l, lt); __quickSort3Ways(arr, gt, r); } void quickSort(int arr[], int n) { srand(time(NULL)); __quickSort3Ways(arr, 0, n - 1); }