排序算法从入门到精通之六--快速排序

9 篇文章 0 订阅
6 篇文章 0 订阅


快速排序的算法是一种分而治之的算法,是一个递归算法。在通常情况下,快速排序算法是已知的最快的算法,故称这个算法为快速排序。通常情况指数据的分布比较平均,关键的的范围比较大。当关键字为升序或者逆序,归并排序比快速排序快的多。当关键字的范围非常窄,计数排序的时间复杂度可低至O(n).
其方法是:
1.首先找出一个枢轴元素base。
2.扫描待排序的数组,将这个数组划分为2部分,使左部分的所有元素小于等于base,右部分的所有元素大于base。
3.对左部分的子数组继续做这个操作。
4.对右部分的子数组做同样的操作。
5.继续递归下去,直到数组的长度小于为1.

下面的代码是这个算法的一个实现。其核心为partition_sort函数,这个函数的对数组的一个子区间 [low,high]做一个扫描。
这个算法取arr[low]作为枢轴元素,采用双向扫描方法。
如果元素大于等于枢轴元素则向左扫描,right--, 如果元素小于枢轴元素,则向右扫描,left++。
扫描结束后将原始区间[low,right] 分为3个子区间,[low,left-1], 中间区间[left,left],只包括一个元素,右区间[left+1,high],然后递归调用partition_sort对左右区间做同样的处理。
下面的代码中,当区间长度小于等于INSERT_SORT_THRESHOLD,调用插入排序算法。

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

void partition_sort(ELE_TYPE arr[], int low, int high)
{
	ELE_TYPE base;
	int left,right;
	
	if ( high-low+1 <= INSERT_SORT_THRESHOLD)
	{
		insert_sort(arr+low, high-low+1);
		return ;
	}

	left=low;right=high;
	base= arr[low];
	
	while (right>left)
	{
		while (right>left && arr[right]>= base)
			right--;
		
		if ( right>left)
		{	arr[left]=arr[right];	left++;}	// fill the hole, the hole is arr[left]

		while (left<right && arr[left]< base)
			left++;
		
		if ( left<right)
		{
			arr[right]=arr[left];	right--;	// fill the hole, the hole is arr[right]
		}
	}

	arr[left]=base;		// now, the left==right
	partition_sort(arr,low, left-1);
	partition_sort(arr,left+1, high);
}

void quick_sort(ELE_TYPE arr[], int len)
{
	partition_sort(arr,0,len-1);
}

void test_quick_sort()
{
	ELE_TYPE arr[] = { 61, 17, 29, 22, 34, 60, 72, 21, 50, 1, 62 };
	int len = (int) sizeof(arr) / sizeof(arr[0]);
	
	printf("original data are:");
	print_array(arr, len);

	quick_sort(arr, len);
	printf("The data after sorted are:");
	print_array(arr, len);	
}

上面的实现是一个最简单的版本。但是这个版本有个缺点。对于特定的数据分布,如数组是严格的非递减序列或者非递增序列,这个算法的递归深度会增加到n,n为数组长度。时间复杂度增加到O(n^2),空间复杂度增加到O(n)。性能变差还是小事儿,要命的是,由于栈的空间比较小,当数组较大时,会导致栈溢出,程序崩溃。

为了解决问题,人们想出各种方法。一种方法是,在序列中随机选择一个元素作为枢轴元素。另一种方法是,选择数组最左,中间,最右的三个元素的中间值作为枢轴,简称三者取中法。

对数组的扫描方法也不限于双向扫描。算法导论(第二版)第7章 给出的方法是
采用自左向右的方向扫描数组, 将待排序的数组分为3部分,左边的部分<=x, x为枢轴元素,中间的部分>x,右边的部分为未排序部分。
 

下一篇 排序算法从入门到精通之七--归并排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值