排序——快排

目录

1.1 确定关键值key(作为基准值)的正确位置

方法1:hoare

 方法2:挖坑法

方法三:双指针法

1.2  对key值的选择进行优化

方法1:三数取中

方法2:随机选key

1.3  进行递归


1.1 确定关键值key(作为基准值)的正确位置

目的:确保排序后数组中比key值小的数字在key之前,比key值大的数字在key之后。

如下图所示:

方法1:hoare

right先向前移动,找到比key小的位置;left再向后移动,找到比key大的位置;交换right和left指向的元素

重复上述步骤,直至left和right相遇,将此时指向的值与key交换。 

 

int PartSort1(int* a, int left, int right) {
	//用keyi表示key的下标值
	int keyi = left;
	while (left < right) {
		//先从右开始找小
		while (left < right && a[right] > a[keyi]) {
			right--;
		}
		//再从左开始找大
		while (left<right && a[left]<=a[keyi]) {
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[keyi], &a[left]);
	//更新keyi
	keyi = left;
	return keyi;
}

运行测试:

可以看出比3小的数字均在3之前,比3大的数字均在3之后。因此3的位置正确!

 方法2:挖坑法

先将key值(即 8)保存到临时变量key中,此时形成一个坑位

先将right向前移动,找到比key小的数值 ,将该数值存入坑位中,right指向的位置此时形成新的坑位。

  

再将left向后移动,找到比key大的数值 ,将该数值存入坑位中,left指向的位置此时形成新的坑位。

重复上述步骤,直到left与right相遇,将key值存放到此时的坑位中。

int PartSort2(int* a, int left, int right) {
	//使用临时变量存放key值
	int key = a[left];
	//使用hole下标表示坑位位置
	int hole = left;
	while (left < right) {
		//先从右开始找小
		while (left<right && a[right]>key) {
			right--;
		}
		a[hole] = a[right];
		//更新hole
		hole = right;
		//再从左开始找大
		while (left < right && a[left] < key) {
			left++;
		}
		a[hole] = a[left];
		hole = left;
	}
	a[hole] = key;
	return hole;
}

运行测试:

成功!

方法三:双指针法

定义两个指针prev和cur:

初始状态,prev指向key值(即数组的第一个元素),cur指向数组的第二个元素;

当cur指向的值比key小,prev++,cur指向的值和prev指向的值进行交换,cur++;

当cur指向的值比key大,cur++

当cur指向数组的最后一个元素时,将prev指向的数值与key值交换

int PartSort3(int* a, int left, int right) {
	//定义两个指针prev,cur
	int prev = left;
	int cur = left + 1;
	int keyi = left;
	//进行循环
	while (cur <= right) {
		while(a[cur] < a[keyi]) {
			prev++;
			Swap(&a[prev], &a[cur]);
			cur++;
		}
/*
也可以写成
    if(a[cur] < a[keyi]) {
			prev++;
			Swap(&a[prev], &a[cur]);
		}
*/
/*
优化后(防止自己与自己进行比较)
    if(a[cur] < a[keyi]&&++prev!=cur) {
			Swap(&a[prev], &a[cur]);
		}
*/
		cur++;
	}
	Swap(&a[prev], &a[keyi]);
//更新keyi
    keyi=prev;
    return keyi;

}

 运行测试:

成功!

1.2  对key值的选择进行优化

方法1:三数取中

目的:在数组有序或接近有序的情况下,选择中间的数字可以使快排的效率更高

选择数组首元素、尾元素和中间位置的元素中,数值处于中间的元素。

两两进行比较,代码如下:

//得到中间数值的元素下标
int GetMidNumi(int* a, int left, int right) {
	//找到中间元素的下标
	int mid = (left + right) / 2;
	if (a[left] < a[mid]) {
		if (a[mid] < a[right]) {
			return mid;
		}
		else if (a[left] < a[right]) {
			return right;
		}
		else
			return left;
	}
	else {
		if (a[mid] > a[right]) {
			return mid;
		}
		else if (a[left] < a[right]) {
			return left;
		}
		else
			return right;
	}
}

方法2:随机选key

目的:防止数组元素有序或接近有序时,key值为最小值(数组的首元素),快速排序效率降低

int RandomNumi(int* a, int left, int right) {
	int randi = left + rand() % (right - left);
	return randi;
}

1.3  进行递归

选取每一个区间的key值,使其排序到正确的位置,直到区间中只包含一个元素或者区间不存在。

如下图所示,keyi将区间划分为两部分---[begin,keyi-1]    keyi    [keyi+1,end]

先递归[begin,keyi-1],再递归[keyi+1,end]

 

 图中红色方框标记出的条件为终止条件,

我们可以将终止条件总结为 begin>=keyi-1 || keyi+1>=end

即区间左下标大于区间右下标

void QuickSort(int* a, int left, int right) {
	if (left >= right) {
		return;
	}
	int keyi = PartSort1(a,left,right);
	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi + 1,right);
}

运行测试:

int main() {
	int b[] = { 8,6,7,11,5,3,9,10 };
	QuickSort(b, 0, 7);
	PrintArray(b, 8);
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值