快速排序

转自:C++经典排序算法总结

假设我们现在对“6  1  2 7  9  3  4  5 10  8”这个10个数进行排序。首先在这个序列中随便找一个数作为基准数(不要被这个名词吓到了,就是一个用来参照的数,待会你就知道它用来做啥的了)。为了方便,就让第一个数6作为基准数吧。接下来,需要将这个序列中所有比基准数大的数放在6的右边,比基准数小的数放在6的左边,类似下面这种排列:

3  1  2 5  4  6  9 7  10  8

在初始状态下,数字6在序列的第1位。我们的目标是将6挪到序列中间的某个位置,假设这个位置是k。现在就需要寻找这个k,并且以第k位为分界点,左边的数都小于等于6,右边的数都大于等于6,递归对左右两个区间进行同样排序即可。想一想,你有办法可以做到这点吗?这就是快速排序所解决的问题。

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。它的平均时间复杂度为O(nlogn),最坏时间复杂度为O(n^2).

首先上图:

 

 从图中我们可以看到:

left指针,right指针,base参照数。

其实思想是蛮简单的,就是通过第一遍的遍历(让left和right指针重合)来找到数组的切割点。

第一步:首先我们从数组的left位置取出该数(20)作为基准(base)参照物。(如果是选取随机的,则找到随机的哨兵之后,将它与第一个元素交换,开始普通的快排)

第二步:从数组的right位置向前找,一直找到比(base)小的数,如果找到,将此数赋给left位置(也就是将10赋给20),此时数组为:10,40,50,10,60, left和right指针分别为前后的10。

第三步:从数组的left位置向后找,一直找到比(base)大的数,如果找到,将此数赋给right的位置(也就是40赋给10),此时数组为:10,40,50,40,60, left和right指针分别为前后的40。

第四步:重复“第二,第三“步骤,直到left和right指针重合,最后将(base)放到40的位置, 此时数组值为: 10,20,50,40,60,至此完成一次排序。

第五步:此时20已经潜入到数组的内部,20的左侧一组数都比20小,20的右侧作为一组数都比20大, 以20为切入点对左右两边数按照"第一,第二,第三,第四"步骤进行,最终快排大功告成。

快速排序代码如下

#include<iostream>
#include<algorithm>
#include<ctime>

using namespace std;

void OutNum(int *nNum, size_t len)
{
	for (size_t i = 0; i < len; i++)
		cout << nNum[i] << ' ';
	cout << endl;
}

void QuickSort(int* nNum, int nLeft, int nRight)
{
	//处理异常数据
	if (NULL == nNum || nLeft < 0 || nRight < 0)
		return;

	// 递归结束条件
	if (nLeft >= nRight)
		return;

	//防止有序队列导致快速排序效率降低 
	srand((unsigned)time(NULL));
	int nLen = nRight - nLeft;
	int nKeyIndex = rand() % (nLen + 1) + nLeft;
	swap(nNum[nLeft], nNum[nKeyIndex]);

	int nBase = nNum[nLeft];
	int nFlagLeft = nLeft;
	int nFalgRight = nRight;

	while (nFlagLeft < nFalgRight)
	{
		// 从后往前找,第一个比基准小的数
		while (nFlagLeft < nFalgRight && nNum[nFalgRight] >= nBase) {
			nFalgRight--;
		}
		if (nFlagLeft < nFalgRight) {
			nNum[nFlagLeft] = nNum[nFalgRight];
		}

		// 从前往后找,第一个比基准大的数
		while (nFlagLeft < nFalgRight && nNum[nFlagLeft] <= nBase) {
			nFlagLeft++;
		}
		if (nFlagLeft < nFalgRight) {
			nNum[nFalgRight] = nNum[nFlagLeft];
		}
	}
	nNum[nFlagLeft] = nBase;

	// 递归调用
	QuickSort(nNum, nLeft, nFlagLeft - 1);
	QuickSort(nNum, nFalgRight + 1, nRight);

}

int main()
{
	//int nNum[10] = {1,7,4,5,3,8,6,9,0,2};
	//int nNum[10] = { 0,1,2,3,4,5,6,7,8,9 };
	//int nNum[10] = { 0,1,2,3,4,5,6,7,9,8 };
	int nNum[20] = { 20,40,50,10,60, 1,7,4,5,3 };

	QuickSort(nNum, 0, 9);

	OutNum(nNum, 10);
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值