【C语言】Select排序

目录

选择排序的定义

选择排序的优化

 那么,根据我们上面的思想可以写出下面的遍历一次的代码如下:

一次走完了之后,我们就该去想想它们停止的条件了:

代码结合初次实现:

产生Bug了!!!

最终实现代码:


选择排序的定义

选择排序,就是将从一组数据的最左边开始(最右也行),然后向右(左)遍历一遍,在找到最大(最小)的那个数据的时候,将其放在最初的位置(末尾),然后再回到其后一个(前一个)位置,再重新遍历,接着找出最大(最小).......把全部的数都遍历了之后,其数据也就有序了。

选择排序的优化

既然在选择排序中,每遍历一次就得找出一个最大或最小的值,那么我们可不可以将其两个极值都先找出来,然后分别放在数据的最左边和最右边呢?在当其左右遍历的值相同时或刚错过时停止。到这时,数据是不是也是有序的呢?

假设,我们将对下面这组数据进行选择排序。

 那么,根据我们上面的思想可以写出下面的遍历一次的代码如下:

void Swap(int* child, int* parent) {//交换数组中下标为child和parent的值

	int  tmp;
	tmp = *child;
	*child = *parent;
	*parent = tmp;

}

void SelectSort(int* a, int n) {

       int begin = 0, end = n - 1;

       //这里得让min和max的值初始化为一个相同的值,否则可能会在遍历比较的时候有产生遗漏或不准确。
		int min = begin, max = begin;
		

		//遍历找出begin和end之间的最大值和最小值的下标
		for (int i = begin + 1; i <= end; i++) {

			if (a[i] < a[min]) {
				min = i;
			}

			if (a[i] > a[max]) {
				max = i;
			}
		}


		//到这就找到了最大值和最小值的下标
		//然后将最大值放在最右边,最小值放在最左边。
		Swap(&a[begin], &a[min]);

		Swap(&a[end], &a[max]);
		

		//最后,再进一步begin和end之间的范围。
		begin++;
		end--;

}

一次走完了之后,我们就该去想想它们停止的条件了:

假如这组数据为偶数个时,从左右两边开始遍历,它们会错过

当其数据为奇数个时,从左右两边开始遍历,其会相遇。

这就是其停止遍历的条件了。

代码如下:

while (begin < end) {//当数组为偶数个时,begin和end会错过。当为奇数个时,会相遇。


}

代码结合初次实现:

    assert(a);

	int begin = 0, end = n - 1;

	while (begin < end) {//当数组为偶数个时,begin和end会错过。当为奇数个时,会相遇。

		//这里得让min和max的值初始化为一个相同的值,否则可能会在遍历比较的时候有产生遗漏或不准确。
		int min = begin, max = begin;
		

		//遍历找出begin和end之间的最大值和最小值的下标
		for (int i = begin + 1; i <= end; i++) {

			if (a[i] < a[min]) {
				min = i;
			}

			if (a[i] > a[max]) {
				max = i;
			}
		}


		//到这就找到了最大值和最小值的下标
		//然后将最大值放在最右边,最小值放在最左边。
		Swap(&a[begin], &a[min]);

		Swap(&a[end], &a[max]);
		

		//最后,再进一步begin和end之间的范围。
		begin++;
		end--;
	}

产生Bug了!!!

以上代码看似好像逻辑上没啥问题,那么我们来运行一下,给我们最初的设置的数据来排下序。

运行结果:

这是咋回事呢?代码写错了么?可是逻辑上好像也没啥问题啊?

别急,让我们来调试一下就清楚了.

其实,在调试中就能发现了,原来我们需要排序的这组数据,其最大值一直就在最左边。

所以从第一次开始遍历到结束,其位置没变过。

但在当进行第一次交换的时候,我们将最小值和其交换了位置,从而导致最终结果排序混乱了。

由此,我们需要在第一次交换之后加上这么一段代码:

if (begin == max) {
			max = min;
		}

意思是:当begin和max下标相同时,其上面一步已经交换了其值,将最大值换到下标为min上去了

最终实现代码:

void SelectSort(int* a, int n) {

	assert(a);

	int begin = 0, end = n - 1;

	while (begin < end) {//当数组为偶数个时,begin和end会错过。当为奇数个时,会相遇。

		//这里得让min和max的值初始化为一个相同的值,否则可能会在遍历比较的时候有产生遗漏或不准确。
		int min = begin, max = begin;
		

		//遍历找出begin和end之间的最大值和最小值的下标
		for (int i = begin + 1; i <= end; i++) {

			if (a[i] < a[min]) {
				min = i;
			}

			if (a[i] > a[max]) {
				max = i;
			}
		}


		//到这就找到了最大值和最小值的下标
		//然后将最大值放在最右边,最小值放在最左边。
		Swap(&a[begin], &a[min]);

		//当begin和max下标相同时,其上面一步已经交换了其值,将最大值换到下标为min上去了
		if (begin == max) {
			max = min;
		}

		Swap(&a[end], &a[max]);
		

		//最后,再进一步begin和end之间的范围。
		begin++;
		end--;
	}

}

运行结果:

至此,选择排序也就结束了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值