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时,数组已经处于有序状态没有必要再循环一次

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

相关推荐
边洛洛3 分钟前
next.js项目部署流程
开发语言·前端·javascript
爱幻想-hjyp10 分钟前
【Python】uv包管理器常用命令
开发语言·python·uv
牛马大师兄18 分钟前
STM32实现低功耗管理使用配置知识梳理笔记
笔记·stm32·单片机·嵌入式硬件·物联网·低功耗
哈皮Superman19 分钟前
【Research】MagicFuzzer: Scalable deadlock detection for large-scale applications
java·开发语言·数据库
lly20240619 分钟前
NoSQL 简介
开发语言
千里马-horse26 分钟前
Boost.Iostreams 简介
开发语言·c++·boost
yi碗汤园37 分钟前
【一文了解】八大排序-冒泡排序、选择排序
开发语言·前端·算法·unity·c#·1024程序员节
二倍速播放40 分钟前
贪心算法 with Gemini
算法·贪心算法
是苏浙44 分钟前
零基础入门C语言之深入了解指针3
c语言·开发语言
陌路201 小时前
C17值类别概念
开发语言·c++