快速排序法C/C++

模板

注:这段代码来自于百度百科。(删除注释)

void sort(int *a, int left, int right)
{
    if(left >= right)return;
    int i = left;
    int j = right;
    int key = a[left];
    while(i < j)
    {
        while(i < j && key <= a[j])
            j--;
        a[i] = a[j];
        
        while(i < j && key >= a[i])
            i++;
        a[j] = a[i];
    }
    a[i] = key;
    sort(a, left, i - 1);
    sort(a, i + 1, right);

解读

1.冒泡排序

在百度百科中有这么一句话:“快速排序(Quicksort)是对冒泡排序的一种改进”。
那么首先我们可以回顾一下冒泡排序的算法:

void bubble(int *a,int len)
{
	int i,j,flag;
	for(i=0;i<len-1;i++)
	{	
		flag=0;
		for(j=0;j<len-i-1;j++)
			if(a[j+1]>a[j])
			{
				swap(a+j+1,a+j);//这个函数中包含了三个元操作
				flag=1;
			}
		if(!flag)return;
	}
}

冒泡排序的核心思想就是相邻两个元素之间比较(两两比较),在两两比较的过程中,我总是把大的元素放在前面,小的元素放在后面,那么经过N次比较,一次遍历过后,最小的元素就被推到了最后面,实际遍历通过下标j,i用于记录已经遍历过的次数(每遍历一次就有一个”极值“被推到某一正确位置,就像气泡一样,大的气泡把小的气泡顶上去。)例下,从小到大排序数组A[5]={5,4,3,2,1}

j/ii=1i=2i=3i=4
j=14,5,3,2,13,4,2,1,52,3,1,4,51,2,3,4,5
j=24,3,5,2,13,2,4,1,52,1,3,4,5
j=34,3,2,5,13,2,1,4,5
j=44,3,2,1,5

不难看出,冒泡排序的最小子问题就是两个元素之间的排序。譬如数组A[4,3,2,1],我想把元素4往上顶,那么按照冒泡排序的算法我得先和元素3进行比较和交换,元素4再和元素2比较和交换,以此类推。在元素4被推向第四个位置时,需要进行3次交换,元素3推向第三个位置需要2次交换,数组A排完序一共需要3+2+1=6次交换。

2.分治思想

既然冒泡排序的最小子问题是两两比较,我们不妨就从两两比较入手,考虑一般排序中最坏的情况——逆序。按照冒泡算法我们需要进行n*(n-1)/2次交换,把这n个数二分,分成两个n/2的逆序列,那么需要2*(n/2)*(n/2-1)/2+n/2次数据交换。我们可以得出结论:在逆序情况下,冒泡排序的事件复杂度是O(n ^ 2),做一次二分后的冒泡排序的时间复杂度是O((n/2)^2 )。同理如果我们做两次二分,那么逆序情况下的时间复杂度还会降低,如果我们一直二分,最后变成两个数之间的排序,此时逆序情况下的时间复杂度最低。那么逆序的二分法有如下图解

在这里,深色为分组,浅色表示排好序。最后其实是把有序的组[4,5],[3],[1,2]在进行排序得到[1,2,3,4,5]。如果把数组A的元素3改成4.5得到一个新的数组B[5,4,4.5,2,1],那么这个上面的排序过程还能解决数组B的排序问题嘛?熟悉排序的人一眼就能看出,在最后排序[4,5],[4.5],[1,2]的时候会有问题,因为4.5应该在4和5的中间,而按分组排序的情况在两两比较时必须满足:i分组中最大元素比ii分组中最小的元素小或者i分组中最小的元素比ii分组中最大的元素大。 显然,第一个逆序的例子是个特殊情况,在乱序的情况下,需要我们对二分的过程进行改进。所以,为了满足刚刚说的条件,我们可以把采用选取中间值的方法,以某一元素为中间值,把大于中间值的数分成一组,把小于等于中间值的数分成另一组。

快排步骤

1.确定首尾,确定关键值
2.以关键值为分界线分成两组
3.重复步骤1,2(确定首尾的值相等或者首小于尾时回溯)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值