双边快排原理:(递增数列)
例 | 2 | 3 | 7 | 9 | 4 | 3 | 1 | 5 | 8 |
一次 | 1 | 2 | 7 | 9 | 4 | 3 | 3 | 5 | 8 |
二次 | 1 | 2 | 3 | 5 | 4 | 3 | 7 | 9 | 8 |
四次 | 1 | 2 | 3 | 5 | 4 | 3 | 7 | 8 | 9 |
五次 | 1 | 2 | 3 | 3 | 4 | 5 | 7 | 8 | 9 |
六次 | 1 | 2 | 3 | 3 | 4 | 5 | 7 | 8 | 9 |
(红色代表选过的基准)
以每个区间最左元素为基准,则从该区间最右开始。(必须从不同与基准数的一边开始)
当从右到左遇到一个数比基准小,则停止。
左边开始向右判断,当遇到一个数比基准大则停止。
左边停止的数与右边停止的数交换,这样就实现了小的数左边放,大的数右边放。
当左右遍历到同一点时,同时停止,基准数与该点的数交换。
此时该点将大区间分为两个小区间,重新取边界值重复以上步骤。
代码实现(可以优化得更简洁,时间复杂度与上述思路相同)
#include<iostream>
using namespace std;
void pivoit(int *p,int l,int r);
int main() {
int a[10];//取十个数排序
for (int i = 0; i < 10; i++) {
cin >> a[i];//赋值
}
int l = 0, r = 9;//双边边界
pivoit(&a[0], l, r);
for (int i = 0; i < 10; i++) {
printf("%d ", a[i]);
}
return 0;
}
void pivoit(int* a,int l,int r) {
if (l>=r) {
return;
}//退出条件:左边界大于等于右边界
int l2 = l, r2 = r, temp;//存放左右边界,方便确定下次排序边界
while (1) {
while (a[r2] >= a[l]) {
r2--;
if (l2 == r2) {
temp = a[r2];
a[r2] = a[l];
a[l] = temp;
break;
}
}
if (l2 == r2) {
break;
}
while (a[l2] <= a[l]) {
l2++;
if (l2 == r2) {
temp = a[r2];
a[r2] = a[l];
a[l] = temp;
break;
}
}
if (l2 == r2) {
break;
}
else {
temp = a[l2];
a[l2] = a[r2];
a[r2] = temp;
}
}
pivoit(&a[0], l, l2-1);
pivoit(&a[0], l2+1, r);//更新边界递归
}