117.【C语言】数据结构之排序(选择排序)

目录

1.知识回顾

2.分析

设想的思路

代码

执行结果

​编辑

错误排查和修复

详细分析出错点

执行结果

3.正确的思路

4.其他问题


1.知识回顾

参见42.5【C语言】选择排序代码 点我跳转

2.分析

知识回顾里所提到的文章的选择排序一次循环只比一个数字,和本文接下来要讲的选择排序有所不同,可以一次循环比较两个数字

如果要比较两个数字,那么就要定义两个下标:left和right,

设想的思路

例如排升序,对于一个无序数组而言,

①每次循环遍历数组,找到最大值和最小值的下标.

②将最小值和数组的第一个元素的值互换,最大值和数组的最后一个元素的值互换.

③left++,right--.

④缩小区间,跳到①执行直到left>=right退出循环,完成选择排序.

示意图:

设想的思路是否正确?有无需要改正的地方?

回答在错误排查和修复里讲了

代码

实现下设想思路的代码

Sort.c写入

cpp 复制代码
void SelectSort(int* arr, int n)
{
	int left = 0;
	int right = n - 1;
	while (left < right)
	{
		int max_i = left;//max_i为最大元素对应的下标,赋的初始值没有严格要求
		int min_i = left;//min_i为最小元素对应的下标,赋的初始值没有严格要求

		//遍历数组,查最大元素和最小元素对应的下标
		for (int i = left+1; i <= right; i++)//注意i循环的区间!
		{
			if (arr[i] > arr[max_i])
			{
				max_i = i;
			}
			if (arr[i] < arr[min_i])
			{
				min_i = i;
			}
		}
		Swap(&arr[left], &arr[min_i]);
		Swap(&arr[right], &arr[max_i]);
		left++;
		right--;
	}
}

main.c写入

cpp 复制代码
#include "Sort.h"
int main()
{
	int arr[] = { 3,5,1,6,2,3,7,9,0,8 };
	printf("排序前:");
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
	SelectSort(arr,sizeof(arr)/sizeof(arr[0]));
	printf("排序后:");
	PrintArray(arr, sizeof(arr) / sizeof(arr[0]));
	return 0;
}

给定数组int arr[]={3,5,1,6,2,3,7,9,0,8}对其使用选择排序

执行结果

选择排序出了问题,"3 5 6 3"并非升序,看来设想的思路是有问题的

错误排查和修复

下断点调试,执行到产生错误之前的状态

-->-->-->-->(问题出在后两步)

即{0,1,2,6,5,3,3,7,8,9}(结束后,下一次循环max_i==,min_i==3)-->{0,1,2,3,5,6,3,7,8,9}

详细分析出错点

从下图的状态开始分析,后面开始单步执行

i从4开始循环,arr[left]恰存储着最大值,最终出循环时,min_i==5,max_i==3,画图可表示为

执行Swap(&arr[left], &arr[min_i])会导致最大值的位置被改变但max_i的下标并没有跟着变,从而导致下一步交换出现问题Swap(&arr[right], &arr[max_i])

因此在下一步交换前先进行判断,如果最大值出现在最左侧(即left==max_i,下标重叠),应该修改max_i的下标

则部分代码改为:

cpp 复制代码
		Swap(&arr[left], &arr[min_i]);
		if (left == max_i)
		{
			max_i = min_i;
		}
		Swap(&arr[right], &arr[max_i]);

这样第一次交换的结果不会影响第二次交换(因此后续的right==min_i不用判断)

执行结果

3.正确的思路

排升序

①每次循环遍历数组,找到最大值和最小值的下标.

②将最小值和数组的第一个元素的值互换,如果出现left等于最大值的下标,应该将最大值的下标赋值为最小值的下标,最大值和数组的最后一个元素的值互换.

③left++,right--.

④缩小区间,跳到①执行直到left>=right退出循环,完成选择排序.

4.其他问题

为什么代码的while (left < right)不写成while (left <= right)呢?

答:当left==right时,数组已经处于有序状态没有必要再循环一次

当然也可以下一个条件断点看一看(数组元素个数必须为奇数,否则无法触发断点)

相关推荐
sealaugh321 小时前
aws(学习笔记第四十八课) appsync-graphql-dynamodb
笔记·学习·aws
黄雪超2 小时前
JVM——函数式语法糖:如何使用Function、Stream来编写函数式程序?
java·开发语言·jvm
ThetaarSofVenice2 小时前
对象的finalization机制Test
java·开发语言·jvm
水木兰亭2 小时前
数据结构之——树及树的存储
数据结构·c++·学习·算法
思则变2 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
lijingguang2 小时前
在C#中根据URL下载文件并保存到本地,可以使用以下方法(推荐使用现代异步方式)
开发语言·c#
¥-oriented3 小时前
【C#中路径相关的概念】
开发语言·c#
Jess073 小时前
插入排序的简单介绍
数据结构·算法·排序算法
老一岁3 小时前
选择排序算法详解
数据结构·算法·排序算法
CoderCodingNo3 小时前
【GESP】C++四级考试大纲知识点梳理, (7) 排序算法基本概念
开发语言·c++·排序算法