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

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

相关推荐
誰能久伴不乏几秒前
Modbus 速查与实战笔记(功能码、帧结构、坑点)
笔记
mit6.82412 分钟前
[邮件服务器core] 安全通信(SSL/TLS) | OpenSSL库管理 | 服务端安全SECURITY.md
c语言·github
长安——归故李22 分钟前
【modbus学习】
java·c语言·c++·学习·算法·c#
索迪迈科技24 分钟前
STL库——map/set(类函数学习)
开发语言·c++·学习
easy202035 分钟前
从机器学习的角度实现 excel 中趋势线:揭秘梯度下降过程
笔记·机器学习·线性回归
Boop_wu36 分钟前
[数据结构] LinkedList
数据结构
ForteScarlet1 小时前
Kotlin 2.2.20 现已发布!下个版本的特性抢先看!
android·开发语言·kotlin·jetbrains
兴科Sinco1 小时前
[leetcode 1]给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数[力扣]
python·算法·leetcode
沐怡旸1 小时前
【算法--链表】138.随机链表的复制--通俗讲解
算法·面试
anlogic1 小时前
Java基础 9.10
java·开发语言·算法