当前位置: 首页 > news >正文

112.【C语言】数据结构之排序(详解插入排序)

目录

1.排序定义

2.插入排序

"插入"的含义

代码

函数框架

函数设计思路

以升序为例,分析插入的三种可能

单趟排序代码

优化后

将单趟排序代码嵌入到循环中

错误代码

两种改法

运行结果

 时间复杂度


1.排序定义

使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作

2.插入排序

"插入"的含义

例如对于一个升序数列:3,4,5,11;现在要求插入7使得数列还能满足升序

显然改动后的数列应该是3,4,5,7,11

算法:设要插入的数字为k,从数列的最后一个元素开始,依次向前比较,直到满足eq?a_n%3Ck%3Ca_%7Bn+1%7D

时,向原数列插入k

代码

小提示:写排序代码时,先写单趟排序,之后将其嵌入循环内,能较容易写出

函数框架

void InsertSort(int* a, int n)
{}

函数设计思路

设tmp为要插入的数字,end为有序数组的最后一个元素的下标,n为无序数组元素的个数,a为数组指针,将tmp插入到[0,end]的区间中,构成有序数列

以升序为例,分析插入的三种可能

①tmp大于所有已经排序的数

②tmp大小介于已经排序的数之间

③tmp小于所有已经排序的数

①tmp大于所有已经排序的数

例如有序数列int arr[]={1,3,5,8,10,21,37,40},此时arr[end]==40;现插入tmp==50,

第一次循环:tmp>arr[end],直接arr[end+1]=tmp,循环结束

②tmp大小介于已经排序的数之间

例如有序数列int arr[]={1,3,5,8,10,21,37,40},此时arr[end]==40;现插入tmp==22

第一次循环:arr[end]==40,tmp<a[end],于是arr[end+1]=arr[end],end--,准备下一次循环

第二次循环:arr[end]==37,tmp<arr[end],于是arr[end+1]=arr[end],end--,准备下一次循环

第三次循环:arr[end]==21,tmp>arr[end],满足条件,arr[end+1]=tmp,循环结束

③tmp小于所有已经排序的数

例如有序数列int arr[]={1,3,5,8,10,21,37,40},此时arr[end]==40;现插入tmp==0

省略前几次循环,第?循环,arr[end]==1,tmp<arr[end],于是arr[end+1]=arr[end],end--,准备下一次循环

如果进行了下次循环,end==-1,会造成越界访问,此时应该立即退出循环!执行arr[end+1]=tmp

显然退出循环有两种情况:1.end<0,即end==-1时 2.tmp>arr[end]

因此将所有可能的情况讨论全,循环退出的条件才能写全

单趟排序代码

	int end;int tmp;while (end >= 0){if (tmp > arr[end]){arr[end + 1] = arr[end];end--;}else{arr[end + 1] = tmp;break;}}if (end == -1){arr[end + 1] = tmp;}

 上面这样写略显麻烦,无论满足什么条件退出循环,最后都执行arr[end + 1] = tmp;

优化后

	while (end >= 0){if (tmp > arr[end]){arr[end + 1] = arr[end];end--;}else{break;}}arr[end + 1] = tmp;

将单趟排序代码嵌入到循环中

main.c写入

int main()
{int arr[] = { 1,6,2,4,7,3,9,0,-1,5 };printf("排序前:");PrintSort(arr, sizeof(arr) / sizeof(arr[0]));InsertSort(arr,sizeof(arr)/sizeof(arr[0]));printf("排序后:");PrintSort(arr, sizeof(arr) / sizeof(arr[0]));return 0;

错误代码

void InsertSort(int* arr, int n)
{for (int i = 0; i < n; i++){int end = i;int tmp = arr[i + 1];while (end >= 0){if (tmp < arr[end]){arr[end + 1] = arr[end];end--;}else{break;}}arr[end + 1] = tmp;}
}

a679a2a764bb4ca79776d2a530ef76fa.png

问题出在越界访问,当i==n-1时,执行int tmp = arr[i + 1];就越界了(arr的最后一个元素是arr[n-1])!!

两种改法

改法1:改for的循环条件

for (int i = 0; i < n-1; i++)

改法2:改tmp和end赋的初始值

	for (int i = 0; i < n; i++){int end = i-1;int tmp = arr[i];//省略......}

备注:循环的一开始,无序数组的首元素可构成一个有序数组,后面的数依次插入有序数组

运行结果

52048fa566a1425094e90e44670c9d82.png

 时间复杂度

最坏情况,每次内循环结束条件都为end==-1,时间复杂度eq?O%28N%5E2%29

最好情况:提供的数组恰好是有序的,时间复杂度eq?O%28N%29

结论:从时间复杂度来看,数组越接近有序,插入排序的时间复杂度越低,而希尔排序就是基于这个结论设计的,有关希尔排序的内容参见下篇文章

 


http://www.mrgr.cn/news/80091.html

相关文章:

  • 【JavaWeb后端学习笔记】Swagger接口调试
  • 简单的多网卡选择指定网卡ip注册
  • 单片机锂电池电量电压检测
  • websocket的配置和使用
  • Redis Cluster 分片机制
  • 数据库数据恢复—ORACLE常见故障有哪些?如何恢复数据?
  • 在 Ubuntu 24.04.1 LTS (WSL) 中使用 openssl 生成 keybox.xml
  • 进程保活机制
  • 深度学习中的多通道卷积与偏置过程详解
  • 零知识证明:区块链隐私保护的变革力量
  • 基于wifipumpkin3的AP伪造
  • Visual Studio 2022+CMake配置PCL1.14.1
  • vite打包失败 - out of memory
  • Vue.js 中,前端如何处理从后端返回的 Excel 文件流
  • vue3+setup使用rtsp视频流实现实时监控,全屏,拍摄,自动拍摄等功能(纯前端)
  • 富士相机基本参数学习
  • Python大数据可视化:基于Python的王者荣耀战队的数据分析系统设计与实现_flask+hadoop+spider
  • React 生命周期
  • TongWe7.0-东方通TongWeb控制台无法访问 排查
  • Tongweb8命令行使用收集(by lqw)
  • [SWPU 2019]漂流记的马里奥
  • Java并发编程实战读书笔记
  • 【h5py】 提取mat文件中的HDF5格式的数据
  • Git-安装与常用命令
  • QT数据库(二):QSqlQueryModel实现数据查询
  • Unity 制作一个视频播放器(打包后,可在外部编辑并放置新的视频)