数据结构与算法 | 直接选择排序、双向选择排序

前几章讲了交换排序中较为复杂切高效的堆排序,这次就来讲讲选择排序中最简单的直接选择排序及其改进双向选择排序。

选择排序:顾名思义,就是主要通过选择来完成的排序,每一趟从待排数据中选择一个最大或者最小的数据,将其放到序列的起始,直到全部数据排完。

直接选择排序的思路是这样的:
例如我们要排升序,我们就假设第一个数据为最小值,将它的下标存入变量min中,如果后面存在比第一个数据还要小的数据,则将那个数据的下标存入min中,然后遍历一次数据,经过不停的更新下标,此时会有两个情况,如果min和起始位置相同,则说明起始点就是最小值,数组不需要变化,而如果不相同,则说明最小值下标更新,我们需要将更新后下标所在的数据和起始下标的数据进行交换,保证最小值归位。

例如我们需要排这样一个数据

int arr[] = {46, 74, 53, 14, 26, 36, 86, 65, 27, 34};

一开始我们保存46的下标0,然后往后遍历,当碰到14时,该数值比46小,所以下标更新为14所在的下标3,然后继续遍历,此时后面不存在比14小的数据,所以14为最小值,与46交换,放到数组首位,14成功归位,第一趟也就这样结束
在这里插入图片描述
因为第一趟最小值归位,第二趟就开始查找次小值,保存74的下标1,向后遍历,不停更新最小值下标,最后Min中保存的下标为26所在的4,两者交换
后面不断重复,因为一趟能使一个数据归位,所以最坏情况下排完全部n个数据需要n - 1趟(因为排完n - 1个后剩下一个也已经归位了)

排序就是如此,只要理解第一趟的思路,就可以以小见大,完成整个排序。

下面进行代码实现

void SelectSort(int *arr, int n)
{
	int i, j, min;
	for(i = 0; i < n - 1; ++i)
	{
		min = i;
		//开始假设最小位置为首位
		for(j = i + 1; j <= n - 1; ++j)
		{
			if(arr[j] < arr[mini])
				mini = j; 
			//如果有更小数据则更新下标
		}
		
		if(min != i)
			swap(&arr[i], &arr[mini]);
		//如果下标发生变化,则将最小值放回正确位置
	}
}

在这里插入图片描述
每趟排序

直接选择排序
时间复杂度:平均情况:O(n^2) 最好情况O(n^2) 最坏情况O(n^2)
空间复杂度:O(1)


直接选择排序的思路就是每趟将一个最小值归位,但是我们不妨想想,如果在一趟中我们既将最小值归位,也将最大值归位,效率是不是更高?

这也就是双向选择排序的思路,每趟同时保存最大和最小下标,设首位为最小,末尾为最大,从两头往中间不断对比交换,一趟就能够将两个数据归位。
(红色为最小值交换,黑色为最大值交换)

在这里插入图片描述
还是刚刚那组数据,第一趟设46的下标0为最小,34下标9为最大,两边往内遍历后锁定最小下标为14的3,和86的6,进行交换

在这里插入图片描述完成第一趟。

第二趟
在这里插入图片描述
同样将74的下标1设为最小下标,27的8设为最大下标,两端往内对比。

但是,这时出现了一个问题,更新后的最大值下标为74所在的1,最小值为26所在的4。这时如上图,74会先和26交换,然后交换过去的26又和27交换,产生了错误,因为两个交换的下标产生了冲突,使得原本归位的26代替74交换到了次大。

所以我们需要考虑到这样一个情况,如果首位为最大值时,我们锁定的最小值与最大值进行交换,交换后,因为最大值位置发生变化,所以下标需要更新,新下标的位置为原本最小值所在的位置,此时将新位置与尾部进行交换,即可完成最大值的归位
在这里插入图片描述
max = min
更新交换后的下标

在这里插入图片描述
第二趟完成

代码实现:

	while(begin < end)
	{
		int min = begin, max = end;
			//双向同时查找最大最小值
		for(i = begin; i <= end; ++i)
		{
			if(arr[max] < arr[i])
				max = i;
			
			if(arr[min] > arr[i])
				min = i;
			//如果有新的最大最小值则更新下标
		}
		
		swap(&arr[begin], &arr[min]);
		
		if(begin == max)
			max = min;
		//如果首位为最大值,且与最小值进行交换,则更新下标
		swap(&arr[end], &arr[max]);
			
		++begin;
		--end;
	}

在这里插入图片描述
每趟排序

双向选择排序
时间复杂度:平均情况:O(n^2) 最好情况O(n^2) 最坏情况O(n^2)
空间复杂度:O(1)

虽然时间复杂度还是O(n^2),但是实际上算法的效率优化了将近40-50%

  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

凌桓丶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值