排序算法——快速排序(ACWing)

原理

基于分治算法

步骤

一个q数组,左边界的下标为l,右边界的下标为r

  1. 确定分界点:x=q[l]或q[(l+r)/2]或q[r]或者一个随机数
  2. 调整区间,所有小于x的数在左边,大于等于x的数在右边
  3. 递归处理左右两个区间

实现方法

  1. 开辟两个新的数组a和b,分别存放小于x的数和大于等于x的数,然后将a、b两个数组合并。
     int k=0,p=0;
     int a[N],b[N];
     int q[N];
     int quicksort(int l,int r)
     {
     x=q[l];
     for(int i=l;i<=r;i++)
     {
          if(q[i]<x)
        {
            a[k]=q[i];
            k++;
        }
        else
        {
            b[p]=q[i];
            p++;
        }
     }
    for(int i=0;i<k;i++)
    {
        q[l+i]=a[i];
    }
    for(int i=0;i<p;i++)
    {
        q[l+k+i]=a[i];
    }
    }
  1. 左边设置一个指针i=l,右边设置一个指针j=r。
    i所指向的元素小于x,i++;
    i所指向的元素大于等于x,停止移动i,去移动j;
    j所指向的元素大于x,j–;
    j所指向的元素小于等于x,停止移动j,i所指向的元素和j所指向的元素交换,i++,j–。
    直到i和j相遇。

    例如:3 1 2 3 5
    0 1 2 3 4
    x=3
    i=-1,j=5
    i++;i=0,j=5;q[i]=q[0]=3,i停止移动,
    j–;i=0,j=4:q[j]=q[4]=5>3,
    j–,i=0,j=3;q[j]=q[3]=3=3,j停止移动,
    q[i]=q[0]=3和q[j]=q[3]=3交换;
    i++;i=1,j=3;q[i]=q[1]=1<3;
    i++,i=2,j=3;q[i]=q[2]=2<3;
    i++,i=3,j=3;q[i]=q[3]=3=3,i停止移动;
    j–;i=3,j=2;q[j]=q[2]=2<3,j停止移动;
    i>j,不能再交换了。
    i>j,停止循环。
    i左边的数(不包括i)都小于等于3,j右边的数(不包括j)都大于等于3。

    #include<iostream>
     using namespace std;
     const int N = 1e6+10;
     int n;
     int q[N];
     void quick_sort(int q[],int l,int r)
     {
         // 区间里面只有一个数或者没有数,就不用排序了
         if(l>=r)
         {
             return;
         }
         int x=q[l];//分界点
         int i=l-1,j=r+1;// 因为是do while循环
         while(i<j)
         {
            do i++; while (q[i]<x);
            do j--;   while (q[j]>x);
            if(i<j)  swap(q[i],q[j]); // swap函数存在于<iostream>文件中
         }
         // 递归排列左右两边
         // 因为左部分小于等于x,右部分大于等于x,所以递归只有两种情况,即sort(l,i-1),sort(i,r);
或者 sort(l,j),sort(j+1,r);
        // 因为对于i来说,i的左边的值是确定的,一定小于等于x,(因为i在j的右边,j右边的值都是大于等于x,所以q[i]一定大于等于x,因为q[i]不能确定是否等于x,而i-1一定可以确定小于等于x,所以递归时只能时sort(l,i-1),sort(i,r);
        // 因为对于j来说,j的右边的值是确定的,一定大于等于x,(因为j在i的左边,i左边的值都是小于等于x,所以q[j]一定小于等于x,因为q[j]不能确定是否等于x,而j+1一定可以确定大于等于x,所以递归时只能时sort(l,j),sort(j+1,r);
        // 当x=q[l]的边界情况:
        // 当只有两个元素时,
        // 例如   1,2
        //        0,1
        // x=1
        // i=-1,j=2
        // i++;i=0,j=2;q[i]=q[0]=1=1,i停止移动
        // j--;i=0,j=1;q[j]=q[1]=2>1;
        // j--;i=0,j=0;q[j]=q[0]=1,j停止移动
        // i=j,q[i]与q[j]不能交换
        // i=j,退出while(i<j)的循环,quick_sort(q,l,i-1)=quick_sort(q,0,-1),quick_sort(q,i,r)=quick_sort(q,0,1)
        // 这时按照代码执行下来,循环之前i=l,退出循环后sort(l,i-1),sort(i,r);等价于sort(l,i-1),sort(l,r);这就跟进入递归时一样了,就导致了死循环,所以此时只能用sort(l,j),sort(j+1,r);
        
      // 当x = q[r]的边界情况
道理类似,如果此时为2,1也会导致j=r,进行sort(l,j),sort(j+1,r);导致死循环(一直sort(l,r),此时只能用sort(l,i-1),sort(i,r);
      // 元素2 1
      // 下标0 1
      // x=1
      // i=-1,j=2
      // i++;i=0,j=2;q[i]=q[0]=2>1,i停止移动
      // j--;i=0,j=1;q[j]=q[1]=1=1,j停止移动
      // q[i]=q[0]与q[j]=q[1]交换
      // i++;i=0,j=1;q[i]=q[0]=1=1,i停止移动
      // j--;i=0,j=1;q[j]=q[1]=2>1
      // j--,i=0,j=0;q[j]=q[0]=1=1,j停止移动
      // i=j,q[i]与q[j]不能交换
      // i=j,退出循环
      // quick_sort(q,l,j)=quick_sort(q,0,1),quick_sort(q,j+1,r)=quick_sort(q,2,1);

     // 当x=q[l+r>>1]的边界情况
此时x取的是序列中间靠左的位置(如果序列个数为奇,则取正中间,如果为偶,则取中间靠左),此时如果元素个数为2,
则中间靠左就是第1个元素,这时就跟x=q[l]的边界情况一致了,所以这时只能用sort(l,j),sort(j+1,r);
     当x=q[l+r+1>>1]的边界情况
此时x取的是序列中间靠右的情况,同理,当元素只有两个,情况就会类似x=q[r],此时只能用sort(l,i-1),sort(i,r);

       // [解释详见](https://blog.csdn.net/xxxxian666/article/details/114818122)         
         quick_sort(q,l,j);
         quick_sort(q,j+1,r);
     }
     int main()
     {
         scanf("%d",&n);
         for(int i=0;i<n;i++)
         {
             scanf("%d",&q[i]);
         }
         quick_sort(q,0,n-1);
         for(int i=0;i<n;i++)
         {
              printf("%d\n",q[i]);
         }
         return 0;
     }

时间复杂度分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值