浅谈快速排序---为您讲解快排模板,并且附上代码注释;

本文详细介绍了快速排序算法,包括其分而治之的思想、图解过程和代码模板。通过一个具体的例题——洛谷P1177,解释了如何应用快速排序解决问题,并给出了完整的解题代码。此外,文章还分享了作者在解决此类问题时的一些心得和经验。
摘要由CSDN通过智能技术生成

目录

一、前言:

二、何为快速排序?

      2.1、思想

       2.2、图解:

        2.3、模板

三、例题:

        3.1、洛谷-P1177-快速排序;

        3.1.1、题解

四、尾声


一、前言:

        Hai~,大家周末晚上好!我是夏日弥,很高兴看见您来读我的博客;

本周将为您带来一些算法基础讲解,从经典的快速排序开始说起吧,我们将依次介绍快排的算法思想和图解,并附上代码模板和相关注释,以及一些网站上的例题;

        让我们开始本周的算法之旅吧!

二、何为快速排序?

      2.1、思想

        快速排序的思想是分而治之(Divide and conquer)——把一个大的问题划分成一个个小问题,再分别处理几个小问题,从而解决大问题。

        我们对一个完全无序的数组做如下操作:

         1、选取一个随机值x,然后设立两根指针 i 和 j 分别指向数组的头部和尾部;

         2、 i 必须指向一个大于 x 的数,否则它将向中间前进一位;

                j 必须指向一个小于 x 的数,否则它将向中间前进一位;

                当 i 和 j 都停下来时,若 i < j 时,交换彼此的值;

         3、完成交换后,强制 i 和 j 往中间移动一位;

         4、当 i 越过了 j 或者 i 和 j 重叠后停止;此时确保这是一个局部有序的数组:

        j 的右边的数全部小于 x ;

        i 的左边的数全部大于 x ;

        5、分别对 i 的左边区域 和 j 的右边区域重复递归 1,2,3,4的步骤;直至整个数列有序;

       

       2.2、图解:

我们将进行1,2,3,4的步骤;

我们来看第一个图解:

       

 然后我们将在期中调一个随机的值作为"分界数",我们叫它x,小夏喜欢取中间的值,所以小夏取3;

我们将设立两根指针分别从数组头部和尾部扫描;

 指针i的使命是指向一个大于x的数字,如果它没有指向这个数字,就让它往右边移动一位;

指针j的使命是指向一个小于x的数字,如果它没有指向这个数字,就让它往左边移动一位;

当两根指针都停下来的时候,如果i<j,即左边的指针没有越过右边的指针,也没有重合的话,就交换它们的位置;

如图;

 您看, i 与 j 只是各取所需而已,i 要确保它的左边所有的元素都小于或者等于x ,

j 要确保它右边的所有元素都大于或者等于x;

当它们指向的元素都不符合自己的需求时,它们就会交换彼此的值;

交换过后,i 与 j 会分别往中间前进一步 ,以免出现以下的死循环

 好了,交换过后必须强制 i 和 j 往中间前进一步!这很重要!

好了,让我们回到刚刚的样例:

 再一次扫描,执行;

 

最后 i 和 j 都指向了3,也就是我们所说的中间值;

您看,i 的左边全部是小于或者等于3的元素对吧!

j 的右边全部是大于或者等于3的元素对吧!

至此,我们完成了第一趟排序;接下来,我们将对 i 左边的区域再次执行一次相同操作的排序;

第二趟排序:

起始位置: 

本次取的中间值是 x = 2;

j 没有指向一个小于 x  的元素,所以把它往前移动;

 

 完成交换后,我们强制 i 和 j 各自往中间移动一位;

如下:

 至此,完成第二趟排序;

再次截取前面的(0,j)区间排序,以此类推,最后您会得到只剩一个数的序列{1},只有一个数的序列当然是有序的;

这个部分也被称为“递归调用”,我们将分别递归(0,j),( j ,  r )的区域,直至整个数列变得有序而完整;

快排的时间复杂度为 N⦁logN;

因此

        2.3、模板

接下来小夏会给您分享一个模板,小夏很喜欢整个模板,因为它足够地“简洁和优雅”;

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;//定义常量N,小夏开的是100010,您可以按照需求随时修改;
 
int n; 
int a[N]; 

void quick_sort(int a[],int l,int r){//参数l是数组开始排序的位置,参数r是排序结束的位置;
	if(l >= r)return ;//如果数组是空的或者它只有一个元素,那么它自然是有序的,返回; 
	int x=a[(l+r)/2];//取一个随机值x,小夏取的是中间值;您可以取头部值或者尾部值都是没问题的;
	 
	int i = l-1,j = r + 1;/*细节问题,小夏采取了强制移动以防止死循环,
	所以在定义i和j时将它们分别往前边和后边移动一位
	*/  
	while(i<j)//左针小于右针时进行; 
	{
		do i++;while(a[i] < x);//先强制移动一位,再判断i指向的值是不是小于x,是的话往前移动; 
		do j--;while(a[j] > x);//先强制移动一位,再判断j指向的值是不是大于x,是的话往前移动;
		if( i < j){
			int tmp = a[i];
			a[i] = a[j];
			a[j] = tmp;
		}//当i和j都停下来,i在j左边时,交换它们指向的值 
	}
	quick_sort(a,l,j);//递归调用,以对前面排序; 
	quick_sort(a,j+1,r);//递归调用,以对后面进行排序; 
} 

int main(){
	scanf("%d",&n);
	for(int i= 0 ;i<n;i++)scanf("%d",&a[i]);
	quick_sort(a,0,n-1);
	for(int i = 0;i<n;i++)printf("%d ",a[i]);
	
	return 0;
}

相关的注释已经为您写好;

三、例题:

        3.1、洛谷-P1177-快速排序;

        【模板】快速排序 - 洛谷

        唔...小夏第一次写这道题也很头疼,因为总是爆时;

         小夏猜了几个原因,可能是数组开得不够大,可能是随机值取得不太好;

        为您附上题目:

        

题目描述

利用快速排序算法将读入的 N\N 个数从小到大排序后输出。

快速排序是信息学竞赛的必备算法之一。对于快速排序不是很了解的同学可以自行上网查询相关资料,掌握后独立完成。(C++ 选手请不要试图使用 STL,虽然你可以使用 sort 一遍过,但是你并没有掌握快速排序算法的精髓。)

输入格式

第 11 行为一个正整数 NN,第 22 行包含 NN 个空格隔开的正整数 a_iai​,为你需要进行排序的数,数据保证了 A_iAi​ 不超过 10^9109。

输出格式

将给定的 NN 个数从小到大输出,数之间空格隔开,行末换行且无空格。

输入输出样例

输入 #1

5
4 2 4 5 1

输出 #1

1 2 4 4 5

        3.1.1、题解

#include<bits/stdc++.h>
using namespace std;
const int N = 1000100;//定义常量N,小夏开的是1000100,您可以按照需求随时修改;
 
int n; 
int a[N]; 

void quick_sort(int a[],int l,int r){
	if(l >= r)return ;//如果数组是空的或者它只有一个元素,那么它自然是有序的,返回; 
	int x=a[(l+r)/2];//取一个随机值x,小夏取的是中间值;您可以取头部值或者尾部值都是没问题的;
	 
	int i = l-1,j = r + 1;/*细节问题,小夏采取了强制移动以防止死循环,
	所以在定义i和j时将它们分别往前边和后边移动一位
	*/  
	while(i<j)//左针小于右针时进行; 
	{
		do i++;while(a[i] < x);//先强制移动一位,再判断i指向的值是不是小于x,是的话往前移动; 
		do j--;while(a[j] > x);//先强制移动一位,再判断j指向的值是不是大于x,是的话往前移动;
		if( i < j){
			int tmp = a[i];
			a[i] = a[j];
			a[j] = tmp;
		}//当i和j都停下来,i在j左边时,交换它们指向的值 
	}
	quick_sort(a,l,j);//递归调用,以对前面排序; 
	quick_sort(a,j+1,r);//递归调用,以对后面进行排序; 
} 

int main(){
	scanf("%d",&n);
	for(int i= 0 ;i<n;i++)scanf("%d",&a[i]);
	quick_sort(a,0,n-1);
	for(int i = 0;i<n;i++)printf("%d ",a[i]);
	
	return 0;
}

(没错啦小夏就是大懒鬼,就是上边的代码,只不过数组开大了一点);

四、尾声

        小夏最近处于严重的怠倦期QAQ,

        还在努力支棱起来;

        已经把大部分的金钱和时间投入可爱键盘上了怎么办啊

        特别鸣谢洛谷提供的例题;

        感谢您的阅读;

        我们下周再见,掰掰~

                                                                                                                                夏日弥死傲娇

                                                                                                                                   2021.11.28;

        

        

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值