快速排序

1、算法思想

选定一个元素作为支点(pivot),以支点为基准将整个序列划分为两个子序列r1 … ri-1和ri+1 … rn,前一个子序列中记录的值均小于或等于支点,后一个子序列中元素的值均大于或等于支点,这个过程称作一趟快速排序(如下图所示)。然后只要分别对这两部分继续进行递归地排序,就可以使整个序列有序。

一趟快速排序的具体做法:
1)、设置两个指针low和high,刚开始分别指向序列的第一个、最后一个的元素。初始化支点(pivot)也为序列的第一个元素。(这是为了方便编程。这里有种错觉:好像pivot只能为第一个元素。其实是可以取序列中的任意一个元素的,只要将选定的元素和第一个元素交换一下就可以了。)
2)、首先,从high所指定位置起向前搜索找到第一个小于pivot的元素和low所指向的元素(即pivot)互相交换,然后从low所指位置起向后搜索,找到第一个大于pivot的元素和high所指向的元素(即pivot)交换。
3)、重复2)中的两步,直到low=high

2、基本算法实现

int partition(int data[], int low, int high)  //返回pivot所在的位置
{
	int pivot = data[low];
	while (low < high)
	{
		while (low < high && data[high] >= pivot) high--;
		swap(data[low], data[high]);  //high指向的值比支点值小,换到前面去。和low指向的值交换也就是和pivot交换

		while (low < high && data[low] <= pivot) low++;
		swap(data[low], data[high]);  //low指向的值比支点值大,换到后面去。此时,high指向的值等于pivot
		                               //和high交换也就是和pivot交换
	}
	return low; //此时low == high。可以发现:pivot其实就是不停地在被“丢来丢去”,不是在high处就是在low处。
	             //所以这里返回high也可以。这也解释了为什么low == high时,算法就停止了,因为low和high指向的value已经是pivot了。
}

void QSort(int data[], int low, int high)     //完整快速排序
{
	if (low < high)
	{
		int pivotloc = partition(data, low, high);
		QSort(data, low, pivotloc - 1);       //递归
		QSort(data, pivotloc + 1, high);      //递归
	}
}

int main(int argc, char *argv[])
{
	int data[20] = { 1, 7, 3, 50, 43, 34, 78, 23, 67, 90 };
	QSort(data, 0, 9);  //调用快排
	int i = 0;
	while (i < 10)   //输出
	{
		cout << data[i] << ' ';
		++i;
	}
	system("pause");
	return 0;
}

3、改进快排算法

上面算法中,每交换一对记录需要进行3次记录移动操作(即swap函数)。从代码和注释中可以看出,其实pivot一直在被“丢来丢去”,所以没有必要一直移动pivot,也就是可以将pivot暂存起来,然后将pivot赋值到最终的位置(一共就修改了4行代码:第5、9、12、14行)。修改版代码如下:
//微改进快排
int partition(int data[], int low, int high)  //返回pivot所在的位置
{
	int pivot = data[low];
	data[0] = pivot;  //暂存
	while (low < high)
	{
		while (low < high && data[high] >= pivot) high--;
		data[low] = data[high];  //第一次执行时,覆盖了pivot,因为pivot已经暂存到data[0]处

		while (low < high && data[low] <= pivot) low++;
		data[high] = data[low];   //由于上一步的执行,data[high]已经复制到了low处
	}
	data[low] = data[0];
	return low;
}

void QSort(int data[], int low, int high)     //完整快速排序
{
	if (low < high)
	{
		int pivotloc = partition(data, low, high);
		QSort(data, low, pivotloc - 1);       //递归
		QSort(data, pivotloc + 1, high);      //递归
	}
}

int main(int argc, char *argv[])
{
	int data[20] = { 0, 1, 7, 3, 50, 43, 34, 78, 23, 67, 90 };  //第0个位置用于暂存pivot
	QSort(data, 1, 10);  //调用快排,对第1—10个位置上的值进行排序
	int i = 1;
	while (i <= 10)   //输出
	{
		cout << data[i] << ' ';
		++i;
	}
	system("pause");
	return 0;
}
下面给出一个一趟快排的例子,也就是partition函数的执行过程。其中i表示low,j表示high,最右边的49表示暂存的pivot,用于进行比较:

参考文献:

《数据结构》,严蔚敏
《算法设计与分析》,王红梅

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值