快速排序
没想到再次回顾快排发现自己对于快排的理解还不是很深入。
快排的时间复杂度为O(nlogn) ~ O(n^2);
若用《数据结构(C语言版)》中的算法:
void Quick_Sort(int *arr, int begin, int end){
if(begin > end)
return;
int tmp = arr[begin];
int i = begin;
int j = end;
while(i != j){
while(arr[j] >= tmp && j > i)
j--;
while(arr[i] <= tmp && j > i)
i++;
if(j > i){
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
arr[begin] = arr[i];
arr[i] = tmp;
Quick_Sort(arr, begin, i-1);
Quick_Sort(arr, i+1, end);
}
每次以第一个数据为参照数,则在数组为逆序时的时间复杂度为O(n^2),递归次数为n-1,而最好的时候(平均递归),递归次数为logn,每次遍历次数都为n。
但是这样子写,在Acwing会被卡,所以有了优化代码:
void quick_sort(int f[],int l, int r)
{
if(l >= r) return;
int i = l - 1, j = r + 1, x = f[l + r >> 1];
while(i < j)
{
do i ++; while (f[i] < x);
do j --; while (f[j] > x);
if(i < j) swap(f[i],f[j]);
}
quick_sort(f , l, j), quick_sort(f , j + 1, r);
//若写成quick_sort(f, l, i - 1), quick_sort(f, i, r); 那么上面的 x = f[l + r + 1 >> 1];上取整
//因为x还是下取整,则可能出现无限循环。
}
这里面的参照数是随机选取的(取的数组中心值),所以在最坏情况下的时间复杂度要小于O(n2)。
补充:(自己写时的一些错误)
#include<iostream>
using namespace std;
int a[100010];
void kp(int a[], int l, int r)
{
if(l >= r) return ;
int x = a[l + r + 1 >> 1];
int i = l, j = r;
while(i < j)
{
while(a[i] < x) i ++;
while(a[j] > x) j--;
if(i < j) swap(a[i],a[j]);
}
kp(a, l,i - 1), kp(a,j,r);
}
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
kp(a,1,n);
for(int i = 1; i <= n; i++)
cout << a[i] << " ";
}
测试代码运行结果如下,没什么问题:

但是提交时,发生错误:

研究发现,当输入【1,1】时,会在while循环体会一直运行,修改如下:
void kp(int a[], int l, int r)
{
if(l >= r) return ;
int x = a[l + r + 1 >> 1];
int i = l, j = r;
while(i < j)
{
while(a[i] <= x) i ++;
while(a[j] > x) j--;
if(i < j) swap(a[i],a[j]);
}
kp(a, l,i - 1);
kp(a,i,r);
}
这时,样例【3 1 2 4 5】都无法通过,研究发现,while(a[i] <= x) i ++; 在一定条件下i++会一直进行。
例如在【1,2】样例中,while(a[i] <= x)一直成立,所以需要添加约束条件(i < j):
while(i < j && a[i] <= x) i ++;
while(i < j && a[j] >= x) j --;
这样也会有问题,【2,1】无法排序。
最后的解决方案为《数据结构(C语言版)》中的算法(见本文第一段代码)。
其实在第一次错误时,直接不加等号,而是改成先自增再判断就解决了。
总结:
1、若采用先判断再自增的方法,则需要像《数据结构(C语言版)》中的算法一样,最后需要手动移动枢轴:
arr[begin] = arr[i];
arr[i] = tmp;
2、若采用先自增再判断的方法,代码见本文第二段代码。

浙公网安备 33010602011771号