快速排序(霍尔法、前后指针法)图文详细

   一  、霍尔法

     快速排序是由冒泡排序改进而得的。在冒泡排序过程中,只对相邻的两个数据进行比较,因此每次交换两个相邻数据时只能消除一个逆序排列。如果能通过两个(不相邻)数据的一次交换,消除多个逆序排列,则会大大加快排序的速度。快速排序方法中的一次交换可能消除多个逆序排列。
算法步骤:

       在待排序的n个数据中任选一个数据(通常选第一个数据)作为基准数,设该基准数位key。n个数据通过与key比较,把比key小的数据交换到前面,把比key大的数据交换到后面,最终将待排序数据分成两个子表,把key放在分界处。然后,分别对左、右子表重复上述过程,直至每个子表只有一个数据时,排序完成。

下图是一趟排序的过程:

(1)选择待排序表中的一个数据作为基准值(通常为第一个数),将基准值暂存在a[0]的位置上。

(2)从数组的最右侧位置依次向左搜索,找到第一个小于基准值的数据,记住下标right的位置(若a[right]的值大于基准值时,则执行right--)。

(3)然后从数组的左侧位置,依次向右搜索找到第一个大于基准值的数据及其下标(若a[left]小于基准值时,则执行left++)。

(4)重复步骤(2)和步骤(3),直至left==right。此时left或right的位置为基准值的最终位置,交换a[left]和基准值a[key],并且使key==left。

具体代码如下:

#include<stdio.h>
void Swap(int* a, int* b) {//交换两个数据的值
	int c = *a;
	*a = *b;
	*b = c;
}
// 快速排序hoare版本
void PartSort1(int* a, int left, int right) {
	if (left >= right) {//循环停止的条件
		return;
	}
	int begin = left, end = right;
	int randi = rand() % (right - left + 1);//产生一个在区间[left,right]中的随机数
	randi += left;
	Swap(&a[left], &a[randi]);
	int keyi = left;//用区间[left,right]中的随机一个数作为基准值

	while (left < right) {
		while (left < right&&a[right] >= a[keyi]) {//left < right--》防止向左寻值时,找不到
			right--;                               //超出区间范围
		}
		while (left < right&&a[left] <= a[keyi]) {
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[left], &a[keyi]);
	keyi = left;
	PartSort1(a, begin, keyi - 1);//[begin,keyi-1]
	PartSort1(a, keyi + 1, end);//[keyi+1,end]
}
int main()
{
	int a[] = { 2,4,6,5,1,3 };
     PartSort1(a, 0, sizeof(a) / sizeof(int) - 1);
	for (int i = 0; i < n; i++) {
		printf("%d ", a[i]);
	}
	return 0;
}

二、前后指针法

前后指针法的主要思想:

        通过创建两个指针(prev和cur),prev指针指向数组的第一个数据,cur指向数组的第二个数据,让cur遍历数组去寻找比基准值a[key]小的数,若找到了,判断prev的下一个位置是否为cur,若prev的下一个位置不是cur,则++prev,交换a[prev]和a[cur]的值,然后++cur,再次遍历数组去寻找比基准值a[key]小的数;若prev的下一个位置是cur,则++prev,++cur(其本质上是先++prev,prev与cur指向同一个数,交换a[prev]和a[cur]的值就是自身与自身交换,然后++cur)。直到cur>right时,交换基准值a[key]和a[prev],使key=prev。

下图是前后指针排序中的一个过程:

key将整个区间分成[left,key-1],[key+1,right]左右两个区间,然后再将这两个子区间进行上述的操作,直至区间只有一个值,这样序列就排好序了。

代码如下:

#include<stdio.h>
void Swap(int* a, int* b) {//交换两个数的值
	int c = *a;
	*a = *b;
	*b = c;
}

// 快速排序前后指针法
void PartSort2(int* a, int left, int right) {

	if (left >= right) {//循环停止条件
		return;
	}
	int prev = left;
	int cur = left + 1;
	int keyi = left;
	while (cur <= right) {
		if (a[cur] < a[keyi] && ++prev != cur) {
			Swap(&a[prev], &a[cur]);
		}
		cur++;
	}
	Swap(&a[prev], &a[keyi]);
	keyi = prev;//keyi将整个区间分成左右两个子区间
	PartSort2(a, left, keyi - 1);//区间[left,keyi-1]
	PartSort2(a, keyi + 1, right);//区间[keyi+1,right]
}
int main()
{
	int a[] = { 2,4,6,5,1,3 };
     PartSort2(a, 0, sizeof(a) / sizeof(int) - 1);
    for (int i = 0; i < n; i++) {
	  printf("%d ", a[i]);
    }
	return 0;
}

代码运行结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过客吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值