【算法】快速排序

前几天实现了插入排序,其时间复杂度为O(N²)。今天来介绍一种新的排序算法,叫快速排序(这些算法都是我在《数据结构》(严蔚敏 吴伟民版)和中国大学MOOC的数据结构视频课学到的,然后线下自己实现了一遍),介绍给大家。


据说快速排序是传说中最快的排序算法,当然,你要是细节实现的不够好,那么它也可能不是快排,而是慢排了!


快速排序的思想是要分而治之,想到这里,估计不少人已=已经想到了递归,没错,我们就是要递归实现它!


比如说我们给了一堆待排元素(图片截取自中国大学MOOC《数据结构》):

                                                                                            

快速排序的做法就是每次从这堆数据中选取一个较为中间的元素作为主元,然后把它分为两大块:

                               

然后,现在序列左边的都是比主元小的,右边的,都是比主元大的。现在,我们再递归的解决左边和右边,就好了!

先写出来我们选取主元的函数:

int find_median(int *a, int left, int right)
{/* 取头中尾的中位数作为主元 */
	int mid = (right - left) / 2 + left;

	if (a[left] > a[mid]) 
		swap(&a[left], &a[mid]);
	if (a[left] > a[right])
		swap(&a[left], &a[right]);
	if (a[mid] > a[right])
		swap(&a[mid], &a[right]);
	swap(&a[mid], &a[right - 1]); //既然已经把这几个数比较了,就把主元放在 right-1 位置,之后直接从 right-2 处开始比较
	return a[right - 1];
}

i 、 j 分别从左右开始比较,最右边的 6 是我们刚刚选取的主元,放在了right-1的位置!

每当i所对应的元素大于了主元,i 就停下,接着 j 开始往左比,当它对应的元素小于主元时,停下来,交换 a[i] 、a[j]

直到 j < i

     

交换 a[i]  和主元

     

这时,左边的序列都比主元小,右边都比主元大,接着,递归的解决左边和右边

void quick_sort(int *a, int left, int right)
{
	int pivot, cutoff, l, r;
		pivot = find_median(a, left, right); //选取主元
		l = left;
		r = right - 1;
		while (1) {
			while (a[++l] < pivot); //从左边开始比较
			while (a[--r] > pivot); //左边停下了,接着从右边比较
			if (l < r) //l 小于 r就交换
				swap(&a[l], &a[r]);
			else
				break; //否则退出循环
		}
		swap(&a[l], &a[right - 1]); //交换 l 对应的元素和主元
		quick_sort(a, left, l - 1); //递归的解决左边
		quick_sort(a, l + 1, right); //递归的解决右边
	
}

还需要注意的是,我们之前说过,一个细节处理不好,它就不是快排,而是慢排了,因为递归是非常耗时的,所以,当递归处理的元素小于一定的数量时,我们再继续用递归解决就不划算了。所以,我们设定一个阈值, cutoff,修改一下程序,当元素个数超过 cutoff 时,我们递归,否则,我们调用其它排序算法:

void quick_sort(int *a, int left, int right)
{
	int pivot, cutoff, l, r;
	cutoff = 100; //这里我选100做阈值就差不多了
	
	if (cutoff < right - left) {
		pivot = find_median(a, left, right);
		l = left;
		r = right - 1;
		while (1) {
			while (a[++l] < pivot);
			while (a[--r] > pivot);
			if (l < r)
				swap(&a[l], &a[r]);
			else
				break;
		}
		swap(&a[l], &a[right - 1]);
		quick_sort(a, left, l - 1);
		quick_sort(a, l + 1, right);
	}
	else
		insert_sort(a + left, right - left + 1); //我之前写的排序算法,函数原型 void insert_sort(int *a, int num) 注意对比参数
                                                       
} 

插入排序详细讲解:http://blog.csdn.net/qq_33724710/article/details/50978480

现在程序执行起来,就更快了!

贴上我测试用的其余代码:

#include <stdio.h>
#include <stdlib.h>

#define N 1000

void insert_sort(int *a, int num)
{
	int tmp = 0;
	int i = 0, j = 0;

	for (i = 1; i < num; i++) {
		tmp = a[i];
		j = i - 1;
		while ((tmp<a[j]) && (j >= 0)) {
			a[j + 1] = a[j];
			j--;
		}
		a[j + 1] = tmp;	
	}
}

void swap(int *a, int *b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

int main(void)
{
	int arr[N] = { 0 };
	int i = 0, data = 1000;

	/*初始化待排数组*/
	for (i = 0; i < N; i++){
		arr[i] = data--;
	}

	/*调用统一接口*/
	quick_sort(arr, 0, N-1);

	/*打印到屏幕*/
	for (i = 0; i < N; i++){
		printf("%d ", arr[i]);
	}

	system("pause");
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fireplusplus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值