排序之插入排序

文章目录

  • 前言
  • 一、直接插入排序
    • 1、基本思想
    • 2、直接插入排序的代码实现
    • 3、直接插入排序总结
  • 二、希尔排序
    • 1、希尔排序基本思想
    • 2、希尔排序的代码实现
    • 3、希尔排序时间复杂度


前言

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。


一、直接插入排序

1、基本思想

直接插入排序是一种简单的插入排序法,其基本思想是:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
例如当有如下一组有序的数组。当分别将10、5、0按照插入排序的思想插入到数组中时,
在这里插入图片描述
此时插入的数据要与数组最后一位进行比较,如果比最后一位大,就插入到数组最后一位的后面;
在这里插入图片描述
如果比数组中最后一位小,就将数组中最后一位元素向后移一位,然后插入的数据与倒数第二个数据进行比较,就这样依次循环下去 。
在这里插入图片描述
如果插入的数据比数组中所有数据都小,此时插入的数据会被插入到数组下标为0的位置,即作为数组的第一个元素。
在这里插入图片描述
上述的操作就是插入排序的单趟排序,即在有序区间,插入一个数使这个区间继续有序。

2、直接插入排序的代码实现

直接写出来插入排序来将数组排序比较困难,我们可以先写出来单趟排序,即当有一个数组的[0,end]有序,把end+1位置的值插入数组中,然后保持数组的[0,end+1]有序。
例如有如下数组。
在这里插入图片描述
此时数组中end+1的值为5,该值小于数组中end位置的值,此时就用tmp记录end+1位置的值,然后将end的值向后移一位,移到end+1位置。然后将end–,此时再将end位置的值与tmp比较。
在这里插入图片描述
此时end位置的值比tmp小,则说明tmp的值就应该插入到end位置之后,此时直接将end+1位置赋值为tmp即可。然后数组中[0,end+1]有序。
在这里插入图片描述
上述就是单趟排序。

void InsertSort(int* arr, int n)
{//[0,end]有序,把end+1位置的值插入,保持有序int end;//将tmp赋值为数组中下标为end+1位置的值int tmp = arr[end + 1];//如果end没有到数组头部,就继续比较while (end >= 0){//如果tmp小于arr[end],就将此时end的数据向后移,然后将end--,使tmp与新的end位置的值比较if (tmp < arr[end]){arr[end + 1] = arr[end];end--;}else{//如果满足条件就跳出循环break;}}//此时end为数组中第一个小于tmp的位置,此时将end+1位置赋值为tmp。//如果当end为-1时,即插入的数据tmp比数组头元素还小,此时end+1刚好为0,即让插入的数据tmp作为新的数组头部。arr[end + 1] = tmp;
}

通过上述的操作我们明白了插入排序排序数组时的单趟操作,当我们有一个长度为n的数组arr时,我们先将end置为0,然后依次将数组首元素之后的元素依次进行插入,当end为n-2时,此时end+1为n-1,即为数组最后一个元素的插入。我们就可以再写一个循环将上面的代码套入其中,并且控制end的值从0到n-2。
在这里插入图片描述

void InsertSort(int* arr, int n)
{int i = 0;//控制end的值,将数组中的元素从首元素后面开始依次进行插入。for (i = 0; i < n-1; i++){//[0,end]有序,把end+1位置的值插入,保持有序int end=i;//将tmp赋值为数组中下标为end+1位置的值int tmp = arr[end + 1];while (end >= 0){//如果tmp小于arr[end],就将此时end的数据向后移,然后将end--,使tmp与新的end位置的值比较if (tmp < arr[end]){arr[end + 1] = arr[end];end--;}else{break;}}//此时end为数组中第一个小于tmp的位置,此时将end+1位置赋值为tmp。//如果当end为-1时,即插入的数据tmp比数组头元素还小,此时end+1刚好为0,即让插入的数据tmp作为新的数组头部。arr[end + 1] = tmp;}}

3、直接插入排序总结

直接插入排序的特性总结:
1.元素集合越接近有序,直接插入排序算法的时间效率越高
2.时间复杂度:O(N^2)
3.空间复杂度:O(1),它是一种稳定的排序算法
4.稳定性:稳定
直接插入排序的最坏时间复杂度为O(N^2),即当数组为逆序时。
最优时间复杂度为O(N),即当数组为顺序有序/接近顺序有序。

二、希尔排序

由上面总结的直接插入排序的最优时间复杂度可知,当数组的顺序接近有序时,直接插入排序的性能可以得到提高,并且能达到O(N)的级别,而希尔排序就是利用了这一点。

1、希尔排序基本思想

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成gap个组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后gap=gap/gap,取gap,重复上述分组和排序的工作。当到达gap=1时,所有记录在统一组内排好序。
希尔排序分为两步。
1、预排序(接近顺序有序)
2、直接插入排序(有序)
例如有如下的一组逆序的数据。
在这里插入图片描述
假设gap为3,即将该组数据分为如图所示的三组数据,
在这里插入图片描述
然后将这三组数据分别进行直接插入排序,此时该组数据的排序虽然没有达到顺序有序,但是相比于原来的逆序,此时该组数据已经接近顺序有序。
在这里插入图片描述
此时将该组数据总体进行直接插入排序,这样相比于原来逆序时就直接进行直接插入排序,效率提高了很多。并且我们可以看出当gap=1时,此时就是进行直接插入排序。

2、希尔排序的代码实现

我们可以像实现直接插入排序一样,先了解希尔排序的一组数据中的单趟排序。
即将分成的3组数据的红色组数据先进行直接插入排序。
在这里插入图片描述

此时将end+gap位置的值赋值为end位置的值。
在这里插入图片描述
然后end = end - gap,此时end已经为负数,但是end+gap为0,刚好为数组的首位,所以将arr[end+gap]的位置存入tmp,即将tmp插入到数组的首位。
在这里插入图片描述
下列代码就实现了上述的操作。

void ShellSort(int* arr, int n)
{int gap = 3;int end = 0;//将tmp赋值为数组中end位置后gap位置的值int tmp = arr[end + gap];while (end >= 0){//如果tmp的值小于此时end位置的值if (tmp < arr[end]){//就将end+gap位置的值赋值为end位置的值,arr[end + gap] = arr[end];//然后将end向后移gap个距离,继续和tmp比较end -= gap;}else{break;}}//此时end位置的值是小于tmp的,将end+gap位置的值赋值为tmparr[end + gap] = tmp;
}

但是上述代码只是将红色数组中的一个数据完成了直接插入排序,下面我们要将红色数组的数据都进行直接插入排序,则需要加一个循环,然后使end的值每次都向后改变。

void ShellSort(int* arr, int n)
{int gap = 3;int i = 0;for (i = 0; i < n - gap; i += gap){int end = i;//将tmp赋值为数组中end位置后gap位置的值int tmp = arr[end + gap];while (end >= 0){//如果tmp的值小于此时end位置的值if (tmp < arr[end]){//就将end+gap位置的值赋值为end位置的值,arr[end + gap] = arr[end];//然后将end向后移gap个距离,继续和tmp比较end -= gap;}else{break;}}//此时end位置的值是小于tmp的,将end+gap位置的值赋值为tmparr[end + gap] = tmp;}}

上述代码只是将红色数组完成了直接插入排序,但是蓝色数组和紫色数组还没有完成直接插入排序,所以需要再次套入一个循环,将蓝色数组和紫色数组也完成直接插入排序操作。此时才算将gap组数都分别在各自组内进行了直接插入排序,此时数组arr中的数据接近顺序有序。

void ShellSort(int* arr, int n)
{int gap = 3;int i = 0;for (i = 0; i < gap; i++){int j = 0;for (j = i; j < n - gap; j += gap){int end = j;//将tmp赋值为数组中end位置后gap位置的值int tmp = arr[end + gap];while (end >= 0){//如果tmp的值小于此时end位置的值if (tmp < arr[end]){//就将end+gap位置的值赋值为end位置的值,arr[end + gap] = arr[end];//然后将end向后移gap个距离,继续和tmp比较end -= gap;}else{break;}}//此时end位置的值是小于tmp的,将end+gap位置的值赋值为tmparr[end + gap] = tmp;}}
}

上述代码嵌套了三层循环,会让人觉得循环太多,其实可以将外面的循环去掉,然后将第二层循环的i += gap变为i++。达到的效果和上面的代码一致,上面代码是将gap组数依次进行直接插入排序,而这个代码是将第一组数的一个进行直接插入排序后,然后将第二组数进行直接插入排序,然后将第三组数进行直接插入排序。这样两个代码达到的效果是一样的。

void ShellSort(int* arr, int n)
{int gap = 3;int j = 0;for (j = 0; j < n - gap; j ++){int end = j;//将tmp赋值为数组中end位置后gap位置的值int tmp = arr[end + gap];while (end >= 0){//如果tmp的值小于此时end位置的值if (tmp < arr[end]){//就将end+gap位置的值赋值为end位置的值,arr[end + gap] = arr[end];//然后将end向后移gap个距离,继续和tmp比较end -= gap;}else{break;}}//此时end位置的值是小于tmp的,将end+gap位置的值赋值为tmparr[end + gap] = tmp;}
}

到这里只完成了希尔排序的第一个步骤,即预排序,而想要将数组中的数据都有顺序,还需要将数组进行直接插入排序。预排序的目的是让数组中的数据达到基本顺序有序,这样使用直接插入排序对数组排序时效率就会提高。
希尔排序的gap该怎么选择呢?
由上面我们可以直到当排升序时,gap越大,大的数更快到后面,小的数可以更快到前面,但是越不接近有序。
排升序时,gap越小,越接近有序,当gap==1时,就是直接插入排序。
当数组中数据为10000个时,此时如果选择gap=3,则预排序和进行直接排序插入的复杂度差不多。当数组中数据为100个时,此时将gap=30,则经过预排序后数组中的数据还是没有达到基本顺序有序。
此时我们可以将gap设置为一个变化的值。

void ShellSort(int* arr, int n)
{int gap = n;int j = 0;//gap>1时都为预排序,并且随着gap越来越小,数组越来越接近有序while (gap > 1){//随着gap越来越小,数组中的数据越接近有序,当gap==1时,就是直接插入排序gap = gap / 3 + 1;  // gap / 3 + 1保证了最后一次gap=1,即最后一次为直接插入排序for (j = 0; j < n - gap; j++){int end = j;//将tmp赋值为数组中end位置后gap位置的值int tmp = arr[end + gap];while (end >= 0){//如果tmp的值小于此时end位置的值if (tmp < arr[end]){//就将end+gap位置的值赋值为end位置的值,arr[end + gap] = arr[end];//然后将end向后移gap个距离,继续和tmp比较end -= gap;}else{break;}}//此时end位置的值是小于tmp的,将end+gap位置的值赋值为tmparr[end + gap] = tmp;}}}

3、希尔排序时间复杂度

希尔排序的时间复杂度很难求,我们只需记住它的时间复杂度接近于O(N^1.3)。
《数据结构(C语言版)》— 严蔚敏
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/72069.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java基础(二十)Stream练习

Stream练习 1. 拼接 给定一个字符串数组,使用 Stream 把所有字符串拼接成一个字符串。 import java.util.Arrays; import java.util.stream.Collectors;public class StringJoinWork01 {public static void main(String[] args) {String[] arr {"a", "b&quo…

IDEA找不到Maven窗口

有时候导入项目或者创建项目时候Maven窗口找不到了 然后指定项目的pom.xml文件

torch.bmm功能解读

bmm 是 batched matrix multiple 的简写&#xff0c;即批量矩阵乘法&#xff0c;矩阵是二维的&#xff0c;加上batch一个维度&#xff0c;因此该函数的输入必须是两个三维的 tensor&#xff0c;三个维度代表的含义分别是&#xff1a;&#xff08;批量&#xff0c;行&#xff0c…

【python手写算法】逻辑回归实现分类(含公式推导)

公式推导&#xff1a; 代码实现&#xff1a; # codingutf-8 import matplotlib.pyplot as plt import numpy as npdef f(w1,x1,w2,x2,b):zw1*x1w2*x2breturn 1/(1np.exp(-z)) if __name__ __main__:X1 [12.46, 0.25, 5.22, 11.3, 6.81, 4.59, 0.66, 14.53, 15.49, 14.43,2.1…

DHCP的interface(接口),global(全局)配置以及DHCP relay(中继),DHCP snooping,DHCP option

目录 1.DHCP的接口&#xff08;interface&#xff09;配置 2.DHCP的全局&#xff08;global&#xff09;配置 3.dhcp relay 4.dhcp snooping 5.option 这里有一个简单的拓扑图 交换机配置命令如下 The device is running!<Huawei> <Huawei>sys Enter system …

Android 动画之插值器PathInterpolator

Android 的View动画、属性动画都可以设置动画插值器&#xff0c;以此来实现不同的动画效果。 这篇文章 Android View动画整理 有介绍各种插值器的效果&#xff0c;这一篇专访 PathInterpolator 。 参考官网 添加曲线动作 &#xff0c; PathInterpolator 基于 贝塞尔曲线 或 …

2023 大学生数学建模竞赛-C题-第一问

题目&#xff1a; 在生鲜商超中&#xff0c;一般蔬菜类商品的保鲜期都比较短&#xff0c;且品相随销售时间的增加而变差&#xff0c; 大部分品种如当日未售出&#xff0c;隔日就无法再售。因此&#xff0c;商超通常会根据各商品的历史销售和需 求情况每天进行补货。 由于商超销…

vue3.2 导出pdf文件或表格数据

要在Vue 3中导出PDF文件&#xff0c;你可以使用第三方库来处理PDF生成和导出。一个常用的库是jspdf&#xff0c;它允许你在客户端或服务器端生成PDF文档。 以下是在Vue 3中使用jspdf库导出PDF文件的基本步骤&#xff1a; 第一步首先&#xff0c;安装jspdf库。你可以使用npm或ya…

macbook如何通过命令行安装软件

作者&#xff1a;吴业亮 博客&#xff1a;wuyeliang.blog.csdn.net 通过命令行安装 macOS 上的 .dmg 文件需要进行一些额外的步骤&#xff0c;因为 .dmg 文件通常需要手动挂载和安装。下面以安装git为例。你可以按照以下步骤进行操作&#xff1a; 将下载的 dmg 文件挂载到文件…

玩转Mysql系列 - 第17篇:存储过程自定义函数详解

这是Mysql系列第17篇。 环境&#xff1a;mysql5.7.25&#xff0c;cmd命令中进行演示。 代码中被[]包含的表示可选&#xff0c;|符号分开的表示可选其一。 需求背景介绍 线上程序有时候出现问题导致数据错误的时候&#xff0c;如果比较紧急&#xff0c;我们可以写一个存储来…

亚马逊鲲鹏系统多渠道引流功能快速增加你的listing流量

如果亚马逊Listing没有流量&#xff0c;那么亚马逊产品排名也会在很靠后的位置&#xff0c;从而就会导致吸引不到客户点击进行下单购买&#xff0c;因此引流就很重要了&#xff0c;普通的引流方法很难达到效果&#xff0c;并且还会花费大量的时间&#xff0c;那么我们可以用亚马…

【postgresql 基础入门】数据库服务的管理,启动、停止、状态查看、配置加载、重启都在这里

数据库服务管理 ​专栏内容&#xff1a; postgresql内核源码分析手写数据库toadb并发编程 ​开源贡献&#xff1a; toadb开源库 个人主页&#xff1a;我的主页 管理社区&#xff1a;开源数据库 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff…

JMeter压力测试 5分钟让你学会如何并发压测接口

文章目录 地址下载启动 使用 地址 JMeter官网下载&#xff1a;https://jmeter.apache.org/download_jmeter.cgi 下载 最新款的jmeter需要java8的支持&#xff0c;请自行安装jdk8或以上的版本 根据系统不同系统下载zip或者是tgz格式的压缩包&#xff0c;并解压&#xff0c;博…

企业互联网暴露面未知资产梳理

一、互联网暴露面梳理的重要性 当前&#xff0c;互联网新技术的产生推动着各种网络应用的蓬勃发展&#xff0c;网络安全威胁逐渐蔓延到各种新兴场景中&#xff0c;揭示着网络安全威胁不断加速泛化。当前网络存在着许多资产&#xff0c;这些资产关系到企业内部的安全情况&#…

【Chrome】chrome浏览器未连接到互联网

问题描述 电脑上安装了一个联想电脑管家&#xff0c;进行了一下清理&#xff0c;并优化了一下启动项&#xff0c;Chrome浏览器突然什么网站都无法访问了。以为更新坏了&#xff0c;但相同的网站放到火狐浏览器上&#xff0c;竟然可以打开&#xff0c;怎么回事呢&#xff1f;怎…

报错:axios 发送的接口请求 404

axios 发送的接口请求 404 一、问题二、分析 一、问题 二、分析 axios 发送的接口请求 404&#xff0c;根本没有把接口信息发送到后端&#xff0c;这个时候你可以查看检查一下自己的接口名字&#xff0c;或让后端配合换一个接口名字再发送一次接口请求 或者重启一下电脑 我是…

微调chatGLM-6B大模型的方法

GLM官方的知乎微调教程&#xff1a;https://zhuanlan.zhihu.com/p/618498001 GLM官方的GitHub微调教程&#xff1a;https://github.com/THUDM/ChatGLM-6B/tree/main/ptuning 说这个微调出的模型和原模型是同时加载的&#xff0c;输入文本的时候会先看看微调出的模型有没有存相应…

c++图论免费ppt,简单深度理解图论

本篇博文想分享一个ppt,是帮助大家简单深度理解c图论. 作者承诺&#xff1a;分享的东西没有病毒&#xff0c;是资料。 分享的东西一个是ppt,ppt里面是150页的&#xff0c;里面将带领大家简单深度理解c图论&#xff0c;还有一个就是里面例题的数据&#xff0c;大家可以按照数据…

Android 9.0 pms获取应用列表时过滤掉某些app功能实现

1.前言 在9.0的系统rom定制化开发中,对系统定制的功能也是很多的,在一次产品开发中,要求在第三方app获取应用列表的时候,需要过滤掉某些app,就是不显示在app应用列表中,这就需要在pms查询app列表时过滤掉这些app就可以了,接下来就实现这些功能 2.pms获取应用列表时过滤掉…

Unity 之利用Audio Source(音频源)组件用于播放声音

文章目录 Unity中的Audio Source&#xff08;音频源&#xff09;是一个用于播放声音的组件&#xff0c;通常附加到游戏对象上&#xff0c;以便在游戏中播放音频效果、音乐或对话。以下是Audio Source的详细介绍&#xff1a; 添加Audio Source&#xff1a; 要在Unity中使用Audio…