快速排序-见解之为什么那么快?

在编程的日常中,排序处处可见。学生分数排序、每本书籍借阅量排序,甚至身高排序,比比皆是。最基本的场景就是,给你一堆数字,让你从大到小,或从小到大,给出他们的排序结果。而输入、输出参数我们都已经了解。下面看下我们是如何实现快排的,而快排为啥又那么快!

 

一般没接触过排序算法的人,正常的做法就是,比如说有N位数,他就会去一次次比较所有的数字,每一次去拿到最大或最小的那个数字,放到数字前面或最后,看例子:

有一串数字:

3,6,9,1,7,4

确定N等于6,我要得到从小到大的排序,首先,我先默认第一个数 3 是最小的那个数,设置a = 3,然后依次比较,找到比 3 还小的数字,第二个是 6,第三个是9,都比 3 大,到了第四个数 1 ,通过比较,1 比 3 小, 这个时候就成  a=1了,接着往下面走,第五个数 7 比1 大,第六个数 4 也比 1 大。然后第一个循环就结束了,这次我们找到了最小的数 1 ,并且知道了它在第四个数上面(比较的时候要记录小的数字在哪个位置上),至此,我们把第四位和第一位上的数字交换位置,成了:

1,6,9,3,7,4

发现了没有,我们通过一次循坏,第一个数字已经归位了,那么所有数字归位,则需要循环6次,由此得知,这个时间复杂度就是 n^2, 而这个排序方法,我们有个名字叫 选择排序。下面是例子:

#include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[])
{
	
	int arr[] = {3,6,9,1,7,4};
	int b ,temp, len = sizeof(arr)/4,n=0;

	for (int i = 0; i < len; ++i)
	{
		b = arr[i];
		for (int a = i+1; a < len; ++a)
		{
			n++;
			if(b > arr[a]){

				arr[i] = arr[a];
				arr[a] = b;
				b = arr[i];
			}
		}


	}

	for (int i = 0; i < len; ++i)
	{
		printf("%d,", arr[i]);
	}
	printf("\n");
	printf("循环次数是: %d\n", n);
	return 0;
}

那么就有同学问了,我们不是在说快速排序吗,怎么说起选择排序来了。我们常说,没有比较就没有伤害,这说法放之四海而皆准。很明显,这上面说选择排序就是用来衬托 快速排序的优越性的。

快速排序,我大概描述下它的处理过程就是,先选定一个数,然后从头尾两边位置上数和选定数的大小比较,然后置换头尾的位置,完成一次操作。这么说有点抽象,下面我们用个例子说明,还是这几个数:

3,6,9,1,7,4

我们先选定数 a =3,然后先从尾部开始,寻找比3小的数,第六个数是4>3,继续第五个数是7>3,继续第四个数是1<3,尾部循环就到此结束。然后我们再从头部第二个数开始,寻找比3大的数字,6>3, 运气不错,第一个就找到,至此,我们分别在头尾找到了比3小,和比3大两个数,于是,我们把这两个数交换位置,如下:

3,1,9,6,7,4

接下来,尾部方向继续走寻找比3小的数,到第三个数9>3,继续第二个数,然后发现跟头部走的方向相遇了,头部也刚好走到第二位数,最后我们把他们在相遇点的数 跟 第一个数交换位置,如下:

1,3,9,6,7,4

到此,我们就完成了一轮循环,那接下来该怎么做呢,只需要重复上面的步骤,根据第一次首尾相遇的点做分割,1 和 9,6,7,4,重复上面的步骤。就能排序,看以下的代码例子:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/**
 * 快排
 */

int arr[]={3,6,9,1,7,4};

void doit(int i,int j){

	if(j <= i){return;}

	int a = i;i = i+1;
	int b=j;

	while(j != i){

		while(j > i && arr[a] < arr[j]){
			j--;
		}

		// 伪代码
		while(j > i && arr[a] > arr[i]){
			i++;
		}

		if(i<j){
			int temp = arr[j];
			arr[j] = arr[i];
			arr[i] = temp;
		}
	}

	int temp = arr[j];
	arr[j] = arr[a];
	arr[a] = temp;
	
	doit(0,j-1);
	doit(j+1,b);
}
int main(int argc, char const *argv[])
{
	
	printf("\n");
	int len=6;

	doit(0,len-1);

	for (int i = 0; i < len; ++i)
	{
		printf("%d,", arr[i]);
	}
	printf("\n");
	return 0;
}

前面一直说,快速排序速度快,不知道同学们有没有发现,快在哪呢? 答案就是: 交换的有效性高,而且交换的次数少,你看快排的每一次交换,就直接定好每个数字的大致位置,是在前面还是后面。而选择排序,每次循环,只能处理一个有效数字,两者相比,高下立判!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值