大于 N 时,交换 arr[T] 与 arr[R-1],R–,不可 T++ !!!!!!!!!!!!
T >= R 时,过程结束。注意,结束条件不能设置为 T==R,因为 R–,T++,可能有 T-R=1
区间内部不保证有序
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
voidnetherLandFlag(int* arr, int size, int N) { int L = -1; int R = size; int T = 0; while (T < R) { if (arr[T] < N) swap(arr[T++], arr[++L]); elseif (arr[T] = N) T++; else swap(arr[T], arr[--R]); } }
loc netherLandsFlag(int* arr, int lower, int upper) { loc bound; if (lower == upper) { bound.left = bound.right = lower; return bound; } int L = lower - 1; int R = upper; int index = lower; while (index < R) { if (arr[index] < arr[upper]) swap(arr[index++], arr[++L]); elseif (arr[index] == arr[upper]) index++; else swap(arr[index], arr[--R]); } swap(arr[R], arr[upper]); bound.left = L; bound.right = R + 1; return bound; }
voidprocess(int* arr, int lower, int upper) { if (lower >= upper) return; loc bound = netherLandsFlag(arr, lower, upper); process(arr, lower, bound.left); process(arr, bound.right, upper); }
注意第 21 行的 swap,容易忽略;
基线条件是 lower>=upper,而不是 lower==upper;
第 29 行,右边界下标为 R+1 而非 R ;
快速排序2.0——随机快排
阅读上文后,读者也许能敏锐地发现,区间的划分情况和 N 息息相关。我们希望,N 总是可以打到数组的中间(数值, 而非位置),这样每次划分就可以达到类似于二分的效果;而一旦数组偏有序,那么划分次数就会大大增加 ,如下:
第 K 层比较次数为 N-K 次,笼统记为 N 次( 只要与 N 线性相关,都记为 N );一共 N-1 层,笼统记为 N 层;所以时间复杂度为 O(N2) 。
如果每次打到中间,就可以产生二分效果,减少划分次数,如下:
第 K 层比较次数为 N-K 次,笼统记为 N 次;一共有 log2N 层( log27=2 ),笼统记为 logN ,故时间复杂度为 NlogN 。
那么如何使 N 刚好打到数组的数值正中间呢?遗憾的是,无法做到,只能随机取值。但好消息是,将 N 随机取值(其值必须为数组中的数)后,该算法的长期期望也可以达到 NlogN 。在最坏状况下则需要次 O(N2) 比较,但这种状况并不常见。
int* generateRandomArr(int max, int len){//生成随机数组 int* arr = newint[len]; for (int i = 0; i < len; i++) arr[i] = rand() % max; return arr; }
voidswap(int& a, int& b) { int tmp = a; a = b; b = tmp; }
loc netherLandsFlag(int* arr, int lower, int upper) { loc bound; if (lower == upper) { bound.left = bound.right = lower; return bound; } int L = lower - 1; int R = upper; int index = lower; while (index < R) { if (arr[index] < arr[upper]) swap(arr[index++], arr[++L]); elseif (arr[index] == arr[upper]) index++; else swap(arr[index], arr[--R]); } swap(arr[R], arr[upper]); bound.left = L; bound.right = R + 1; return bound; }
voidprocess(int* arr, int lower, int upper) { if (lower >= upper) return; swap(arr[upper], arr[rand() % (upper - lower + 1) + lower]); loc bound = netherLandsFlag(arr, lower, upper); process(arr, lower, bound.left); process(arr, bound.right, upper); }
voidquickSort(int* arr, int size) { if (arr == nullptr || size == 1) return; process(arr, 0, size - 1); }
第 57 行,随机交换数组最后和其他某位置的数。
效率比较
测试次数time=10000 ,最大值max=1000000000 ,最大长度size=1000000 ,快速排序 1.0 反而快于随机快排 0.6203 ms :
int* generateRandomArr(int max, int len){//生成随机数组 int* arr = newint[len]; for (int i = 0; i < len; i++) arr[i] = rand() % max; return arr; }
voidswap(int& a, int& b) { int tmp = a; a = b; b = tmp; }
loc netherLandsFlag(int* arr, int lower, int upper) { loc bound; if (lower == upper) { bound.left = bound.right = lower; return bound; } int L = lower - 1; int R = upper; int index = lower; while (index < R) { if (arr[index] < arr[upper]) swap(arr[index++], arr[++L]); elseif (arr[index] == arr[upper]) index++; else swap(arr[index], arr[--R]); } swap(arr[R], arr[upper]); bound.left = L; bound.right = R + 1; return bound; }
voidprocess_1(int* arr, int lower, int upper) { if (lower >= upper) return; loc bound = netherLandsFlag(arr, lower, upper); process_1(arr, lower, bound.left); process_1(arr, bound.right, upper); }
voidquickSort_1(int* arr, int size) { if (arr == nullptr || size == 1) return; process_1(arr, 0, size - 1); }
voidprocess_2(int* arr, int lower, int upper) { if (lower >= upper) return; swap(arr[upper], arr[rand() % (upper - lower + 1) + lower]); loc bound = netherLandsFlag(arr, lower, upper); process_2(arr, lower, bound.left); process_2(arr, bound.right, upper); }
voidquickSort_2(int* arr, int size) { if (arr == nullptr || size == 1) return; process_2(arr, 0, size - 1); }
int* cpyArr(int* src, int len){ int* des = newint[len]; memcpy(des, src, len * sizeof(int)); return des; }
boolisEqual(int* arr_1, int* arr_2, int len){ for (int i = 0; i < len; i++) { if (arr_1[i] != arr_2[i]) returnfalse; } returntrue; }
intmain() { clock_t start_1, end_1,start_2,end_2; srand((unsigned)time(NULL)); int max = 1000000000; int maxSize = 1000000; int times = 10000; int arg=0; for (int i = 0; i < times; i++) { int size = rand() % maxSize + 1; int* arr_1 = generateRandomArr(max, size); int* arr_2 = cpyArr(arr_1, size); start_1 = clock(); quickSort_1(arr_1, size); end_1 = clock();