3、选择排序

基本思想:第一次遍历数组从下标为0的位置开始向后找出最小值(升序),将最小值与初始位置数值相交换,第二次遍历数组从下标为1的位置开始向后找最小值与其交换......直到排完整个数组

 由于该排序需要交换数据,所以做好提前写好交换函数,避免后边代码冗余

 void swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}

注意:交换数据用函数实现需要使用指针

形参只是实参的一份临时拷贝,改变形参不会直接影响实参的数值

由于初始位置在不断后移,可以考虑用循环完成,向后遍历数组寻找最值也需用循环实现,所以可以用镶嵌式循环实现

void SelectSort1(int* a, int n)
{
	int begin = 0;
	while(begin<n)
	{
		int mini = begin;
		for (int i = begin; i < n; i++)
		{
			if (a[mini] > a[i])
			{
				mini = i;
			}
		}
		swap(&a[begin], &a[mini]);
		begin++;
	}
}

 代码可以进一步提高效率,优化,在一次遍历的同时可以找出最大值和最小值,然后同时交换数组的始端和尾端↓

优化

在定义begin控制始端的位置的同时我们也可以定义end来控制尾端的位置

在遍历数组找最小值的同时我们也可以同时找最大值存入新的变量中

int begin = 0, end = n - 1;
	while (begin < end)
	{
		int maxi = begin, mini = begin;
		for (int i = begin; i <= end; i++)
		{
			if (a[i] > a[maxi])
			{
				maxi = i;
			}

			if (a[i] < a[mini])
			{
				mini = i;
			}
		}
        //有bug
		swap(&a[begin], &a[mini]);
        swap(&a[end], &a[maxi]);

但这个代码是有问题的 

 打印的并不是升序,我们可以通过调试来找出问题

刚进入for循环,一切都没有问题

 我们预期遍历一遍后mini=7,maxi=0,发现事实依然没有问题

 接下来就是交换数据了,第一次将最小值和初识位置交换,没问题

 第二次最大值与尾端交换,现在是不需要交换,可是后面的交换代码还没执行,又换回来了,而下次的遍历不再遍历这两个位置,所以问题在这里

 第一次交换是最小值的归位,而maxi和begin重叠,第一次交换就如同swap(&a[maxi],&a[mini]);

最大值与最小值交换了,现在mini是最大值,最小值已经归位,只需在两种交换之间添加一个将mini赋给maxi的代码即可实现

void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		int maxi = begin, mini = begin;
		for (int i = begin; i <= end; i++)
		{
			if (a[i] > a[maxi])
			{
				maxi = i;
			}

			if (a[i] < a[mini])
			{
				mini = i;
			}
		}
		swap(&a[begin], &a[mini]);
		// 如果maxi和begin重叠,修正一下即可
		if (begin == maxi)
		{
			maxi = mini;
		}
		swap(&a[end], &a[maxi]);

		++begin;
		--end;
	}
}

即使优化后选择排序的效率依然较低很少使用

时间复杂度:O(N^2)

空间复杂度:O(1) 

稳定性:不稳定

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值