快速排序

没想到再次回顾快排发现自己对于快排的理解还不是很深入。

  这是Acwing中模板题

  快排的时间复杂度为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、若采用先自增再判断的方法,代码见本文第二段代码。

 

 

 

 

posted @ 2023-07-01 17:11  Geni_w  阅读(27)  评论(0)    收藏  举报