快排和归并 模版 第一课

148 阅读3分钟

快排模版的思想:

先分治,再递归

首先需要找个阈值,或者叫结点,用x来表示。x可以为q[l],q[mid],q[r]任意位置,习惯性放中间: 因为如果正好q[l],q[r]的位置就需要多排几次,时间复杂度会变高,可能会通不过:

image.png image.png

然后就是比x大的就放到x前面,比x小的就放到x后面,这样排完之后,x前面的数肯定比x小,x后面的数肯定比x大。

利用这个思想先用暴力法求解:

需要用到额外空间,首先开辟两个空间:a[N],b[N]

image.png 遍历q[N]的值,如果比q[x]大就放到a[N]里面,否则就放到b[N]里面。 然后分别对a[N],b[N]排序,最后再把它们放回q[N],此时q[N]就是有序数组。

image.png

题目:785. 快速排序 - AcWing题库

暴力解法

#include<iostream>
using namespace std;

const int N=1e6+10;//题目要求数组大小范围为1~10^9,+10的目的是为了防止越界
int n;
int q[N];
int a[N],b[N];


void qsort_t(int q[],int l,int r,int x)
{
    //如果q[i]<q[x]就放a[N],否则就放b[N]

    for(int i=0;i<r;i++)
    {
        if(q[i]<q[x])
        {
            a[i]=q[i];
        }
        else
        {
            b[i]=q[i];
        }

    }


    //给a[N]排序
    for(int i=0;i<x;i++)
    {
        for(int j=i+1;j<x;j++)
        {
            if(a[i]>a[j]) swap(a[i],a[j]);
        }
    }

    //给b[N]排序
    for(int i=x;i<=r;i++)
    {
        for(int j=i+1;j<r;j++)
        {
            if(b[i]>b[j]) swap(b[i],b[j]);
        }
    }


    //再把排好序的还给q[N]
    for(int i=0;i<x;i++)
    {
        q[i]=a[i];
    }
    for(int j=x;j<r;j++)
    {
        q[j]=b[j];
    }


    //打印输出
    for(int i=0;i<=n-1;i++)
    {
        printf("%d ",q[i]);
    }
}

int main()
{


    scanf("%d",&n);

    for(int i=0;i<n;i++)
    {
        scanf("%d",&q[i]);
    }

    int l=0,r=n-1,x=(l+r)/2;//计算x的中间值

    qsort_t(q,l,r,x);

    return 0;
}

image.png

but 第二个测试用例没过:

image.png

优雅的解法:

套用模版,先设个x,然后用双指针求解。

一个左指针指向首地址,一个右指针指向数组末尾。

左指针++,右指针--,如果左指针值大于x,就把值放到右指针位置。

如果右指针值小于x,就把值放到左指针位置。

这样就可以一直保证x前面的值一定小于等于x,x右边一定是小于x的,这样就是一个有序数组。 代码:

#include<iostream>  
using namespace std;  
const int N=1e6+10;  
int n=0;  
int q[N];  
void qsort_t(int q[],int l,int r)  
{
   //如果只有一个数,或者没有数,就不用再比较了  
   if(l>=r)return ;  
   int x=(l+r)/2,i=l-1,j=r+1;  
   while(i<j)  
   {  
       do{ i++;}while(q[i]<q[x]);  
       do {j--;}while(q[j]>q[x]);  
     if(i<j)swap(q[i],q[j]);
   }  
   qsort_t(q,l, j);  
   qsort_t(q,j+1,r);  
}
int main()  
{
   scanf("%d",&n);
   for(int i=0;i<n;i++)  
   {  
       scanf("%d",&q[i]);  
   }  
   
   qsort_t(q,0,n-1);  
   
   for(int i=0;i<n;i++)  
   {  
      printf("%d",q[i]);
   }  
   return 0;  
}

但是这个不能通过全部测试用列:

image.png 原因是

#include<iostream>  
using namespace std;  
const int N=1e6+10;  
int n=0;  
int q[N];  
void qsort_t(int q[],int l,int r)  
{
   //如果只有一个数,或者没有数,就不用再比较了  
   if(l>=r)return ;  
   int x=q[(l+r)/2],i=l-1,j=r+1;  
   while(i<j)  
   {  
       do{ i++;}while(q[i]<x);  
       do {j--;}while(q[j]>x);  
     if(i<j)swap(q[i],q[j]);
   }  
   qsort_t(q,l, j);  
   qsort_t(q,j+1,r);  
}
int main()  
{
   scanf("%d",&n);
   for(int i=0;i<n;i++)  
   {  
       scanf("%d",&q[i]);  
   }  
   
   qsort_t(q,0,n-1);  
   
   for(int i=0;i<n;i++)  
   {  
      printf("%d ",q[i]);
   }  
   return 0;  
}

acwing 归并 - 掘金 (juejin.cn)

acwing算法基础第一课 二分 - 掘金 (juejin.cn)