基本排序(3)——快速排序

 

目录

前言

快速排序hoare版

    代码实现

    挖坑法

代码实现

    前后指针法

代码实现

    优化思路


前言

    快速排序是一种效率非常高的排序方法,排序时需要先取一个基准值。该方法有三种不同实现方式。

快速排序hoare版

    先取一个基准值,一般为了使方法更加简化,我们会取最左边或最右边的元素为基准值,,然后标记前后元素位置,分别比较,(如果是升序)将前边比基准值大的元素与后面比基准值小的元素交换,直到前后标记相遇,第一趟循环结束,循环结束后将两标记相遇处的元素与基准值交换。

    流程:先确定基准值

left移动到比基准值大的值上,right移动到比基准值小的元素上

 

然后left与right交换

 left与right继续移动寻找对应元素

 left与right相遇时第一趟循环结束

 

交换相遇处元素与基准值,可以发现原来的基准值3 左边的元素全都是小于3的,右边全是大于3的

然后left不变,将第一趟相遇处作为第二趟的right,继续重复以上操作

 

    代码实现

int PartSort1(int* a, int left, int right){  //hoare版
	int key = left;  //取最左为基准值
	while (left < right){
		while (left<right && a[right] >= a[key]){ //如果是升序且key是left,则right一定要在left前
			right--;
		}
		while (left<right && a[left] <= a[key]){//如果是降序且key是left,则该循环在前
			left++;
		}
		if (left < right){
			Swap(&a[left], &a[right]);
		}
	}
	Swap(&a[left], &a[key]);
	return left;
}


void QuickSort(int* a, int left, int right){  //快速排序
	if (left >= right)
		return;
	int key = PartSort1(a, left, right);
	QuickSort(a, left, key - 1);  //递归
	QuickSort(a, key + 1, right);
}

    挖坑法

    该方法思路相比以上方法有一点点变化,排序时同样是先找最左或最右为基准值,然后标记前后位置,但是找到左边(或右边)大于(或小于)基准值的元素用于覆盖最右边(左边)(基准值的位置),最后把基准值填在左右标记相遇处。

left找到比基准值大的元素

用left覆盖right位置

 right向前移动找比基准值小的元素,如果left与right不相等则将right覆盖left,直到与left相遇退出

 最后将基准值覆盖在相遇处

第一趟完成后,基准值左边都是小于自身的,右边都大于自身。然后重复以上操作

代码实现

int PartSort2(int* a, int left, int right){ //挖坑法
	int key = a[right];  //取最右为基准值
	while (left < right){
		while (left<right && a[left] <= key){
			left++;
		}
		a[right] = a[left];
		while (left < right && a[right] >= key){
			right--;
		}
		if (left < right)
		    a[left] = a[right];
	}
	a[left] = key;
	return left;
}


void QuickSort(int* a, int left, int right){  //快速排序
	if (left >= right)
		return;
	int key = PartSort2(a, left, right);
	QuickSort(a, left, key - 1);
	QuickSort(a, key + 1, right);
}

    前后指针法

与之前两种方法又有了一点点的区别,排序时设置基准值key和两个指针,一前(cur)一后(prev),只要cur上的元素小于基准值,且prev的下一位元素不是cur,则交换cur与prev,直到cur大于end(最右边)结束循环,然后交换prev与key的值。

取最右边为基准值

 先判断cur是否小于基准值,如果不小于,则后移,prev不动,如果小于则判断prev的下一位是否与cur相同,相同则cur后移。  这里3是小于4的,所以先++prev后prev与cur相同,cur也后移一位

 

 

再判断此时cur小于基准值了,先++prev是等于cur 的,cur后移。

 再判断,cur是5不小于基准值,cur后移,prev不动

 此时cur小于基准值,先++prev(此时prev是5)也不等于cur(此时是2),则交换cur与prev后cur后移

 重复以上判断

 cur与end相遇,退出循环,再交换prev的下一位与基准值的值

 最后再重复以上所有操作,可以看到第一趟结束后基准值4前面都是小于4的,后面元素都大于4

代码实现

int PartSort3(int* a, int left, int right){  //前后指针法
	int key = right;
	int prev = left-1,cur=left; 
      //上面写int prev = left,cur=left+1;,下面写Swap(&a[prev], &a[key]);会出问题
	while (cur < right){
		if (a[cur] <= a[key] && ++prev != cur){
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[++prev], &a[key]);  //需要先++prev再交换
	return prev;

	/* 基准值在前也行,采用降序

	int key = left;//选取第一个元素为基准值
	int prev = left;//前指针
	int cur = prev + 1;//后指针
	whiel(cur <= end)
	{
		if(array[cur] > a[key] && ++prev != cur)//如果cur的值小于key判断++prev的值是否等于cur
			//若不等于,则交换prev和cur的值
			swap(&a[cur],&a[prev]);
		cur++;//cur向后移动
	}
	//当跳出循环时,说明prev及之前的值都是小于基准值的数,则交换prev指向的值和基准值
	swap(&a[++prev], &a[key]);
	return prev;//返回此时基准值的下标,便于下次递归调用时分组

	*/
}


void QuickSort(int* a, int left, int right){  //快速排序
	if (left >= right)
		return;
	int key = PartSort3(a, left, right);
	QuickSort(a, left, key - 1);
	QuickSort(a, key + 1, right);
}

    优化思路

    可以使用三数取中法(即比较最左,最右,和中间三个数的大小,选择三个数中数值为中间的那个作为基准值),这样可以提高些许效率。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值