11 插入排序和希尔排序

1. 插入排序

基本思想
直接插入排序是一种简单的插入排序法,基本思想:

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列

在玩扑克牌时,就用了插入排序的思想

在这里插入图片描述

过程
在这里插入图片描述

类似扑克牌,手里有3,7,8,9,,四张牌,这时,如果摸到4,怎么排它的位置。先和9比,小于9,再和前面的8比,再和7比,再和3比,这时大于3,就找到了它该插入的位置,将4放在3的后面,其他的往后挪一个

在这里插入图片描述

从7开始排,第一个数肯定是有序的。
然后是4,4小于7,所以7应该在4的前面,将7往后挪一位,4放在7的位置
5比7小,7往后挪,5比4大,所以5的位置就是4的后面

这样不断比较,直到最后一个数排完

void Sort(int ary[], int len)
{//第一个是有序的,从第二个开始for (int i = 1; i < len; i++){//[0,end]的区间是有序的,end是待排序数的前一个下标int end = i - 1;int temp = ary[i];while (end >= 0){if (ary[end] > temp){ary[end + 1] = ary[end];end--;}else{break;}}//此时,end是前一个位置ary[end + 1] = temp;}}

特性总结:
1.元素集合越接近有序,直接插入排序算法的时间效率越高
2.时间复杂度:最坏O(N2),逆序的时候最坏,最好是O(N),正序的时候
3.空间复杂度: O(1)
4.稳定性:稳定

插入和冒泡
两者在最好和最坏的情况下时间复杂度相同,但对于大部分有序,局部无序的情况下,插入的适应性更强
在这里插入图片描述

上面的数据只有最后面的9和8无序,对于冒泡排序来说,需要第一轮比过去,交换8和9,第二轮到9的位置后发现有序,排序完毕。插入排序来说,检查到8的时候,一交换,排序完毕。这时,插入排序的效率高。冒泡排序更容易理解,比较容易上手

2. 希尔排序

基本思想
希尔排序又称缩小增量法,基本思想是:先选定一个整数,把待排序文件中所有记录分成几个组,对每一组内的记录进行排序。然后缩小分组间隔。重复上述过程,当增量缩小到1时,所有记录排为一组,排好序

插入排序对大部分有序的数据效率很高,但对于倒序的效率很低。可以根据这个特性优化。先对数据用一种效率高的方法进行预排序,使数据接近有序。最后再进行一次插入排序,就可以排序成功

过程
在这里插入图片描述
首先将整个数组按间隔gap分组,分为gap组,这里以间隔3分组

在这里插入图片描述

上面的从9开始每间隔3分为归为一组,9,6,3,1分到了一组

然后从8开始分组,直到将所有数据分组完
在这里插入图片描述
以颜色区分分为了3组,首先写一个类似的插入排序对红色组排序

void ShellSort(int ary[], int len)
{
//间隔3int gap = 3;
//0,从end+gap开始往前对比,到组内最后一个数排完,每次加间距for (int i = 0; i < len - gap; i += gap){int end = i;int temp = ary[gap + end];
//将gap+end下标,也就是组内下一个数和前面的所有对比交换while (end >= 0){if (ary[end] > temp){ary[gap + end] = ary[end];end = end - gap;}else{break;}}ary[end + gap] = temp;}	
}

在这里插入图片描述
将红色组排好了序,接着将其他两组也排好序,意味着需要循环组数的次数,控制变量i

	int gap = 3;//循环gap组for (int j = 0; j < gap; j++){//从end+gap开始往前对比,找组内下一个数,每次加间距for (int i = j; i < len - gap; i += gap){int end = i;int temp = ary[gap + end];//将gap+end下标,也就是组内下一个数和前面的所有对比交换while (end >= 0){if (ary[end] > temp){ary[gap + end] = ary[end];end = end - gap;}else{break;}}ary[end + gap] = temp;}}}

在这里插入图片描述

上面的数字仍是无序的,但经过预排序已经大部分有序

上面的三层循环可以减到2层循环,最外层的循环可以去掉。实际上外面两层循环本质上是把所有数据遍历了一遍,所以可以只用一层,多组并排,i每次递增1

void ShellSort(int ary[], int len)
{int gap = 3;//从end+gap开始往前对比,找组内下一个数,每次加间距for (int i = 0; i < len - gap; i++){int end = i;int temp = ary[gap + end];//将gap+end下标,也就是组内下一个数和前面的所有对比交换while (end >= 0){if (ary[end] > temp){ary[gap + end] = ary[end];end = end - gap;}else{break;}}ary[end + gap] = temp;}
}

怎么让大部分有序的数据变为有序,只需要控制gap的变化,当gap=1时,就是插入排序。gap应该根据数据量变化,数据量大的时候,gap的跳跃变大,gap越大,越接近无序,但可以更快的将更大更小的数放在两端的位置

为了使排的数据最终变有序,gap的值最后必须可以变为1,官方给出的是gap每次/3+ 1,当gap为2时,就变为0,所以/3后再加1,这样无论多少数据,最终都会分为一组

void ShellSort(int ary[], int len)
{int gap = len;//gap>1预排序//gap=1插入排序while (gap > 1){//+1保证最后一次是1//gap = gap/2gap = gap / 3 + 1;//从end+gap开始往前对比,找组内下一个数,每次加间距for (int i = 0; i < len - gap; i++){int end = i;int temp = ary[gap + end];//将gap+end下标,也就是组内下一个数和前面的所有对比交换while (end >= 0){if (ary[end] > temp){ary[gap + end] = ary[end];end = end - gap;}else{break;}}ary[end + gap] = temp;}}}

时间复杂度
在这里插入图片描述
gap/3这一层时间复杂度log3N,因为每次都除以3。而对于里面的两个循环,时间复杂度计算比较麻烦,大致可认为是O(N)。因为gap每次都是变化的,且前面的排序对后面排序的增益效果无法估算
在这里插入图片描述
上面只能以最坏的情况计算,但gap越小,情况应该是越好的

特性
1.希尔排序是对直接插入排序的优化
2.当gap>1时是预排序,目的是让数组更接近有序。gap==1时,数组已经接近有序了,就会很快
3.时间复杂度: O(N1.3)
在这里插入图片描述

在这里插入图片描述

3.稳定性: 不稳定

3. 插入排序和希尔排序比较

随机生成10万个数字,计算两个排序所消耗的时间,大致差了100倍
在这里插入图片描述

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

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

相关文章

【开源】JAVA+Vue+SpringBoot实现学生综合素质评价系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生功能2.2 教师功能2.3 教务处功能 三、系统展示四、核心代码4.1 查询我的学科竞赛4.2 保存单个问卷4.3 根据类型查询学生问卷4.4 填写语数外评价4.5 填写品德自评问卷分 五、免责说明 一、摘要 1.1 项目介绍 基于J…

vite, vue3, vue-router, vuex, ES6学习日记

学习使用vitevue3的所遇问题总结&#xff08;2024年2月1日&#xff09; 组件中使用<script>标签忘记加 setup 这会导致Navbar 没有暴露出来&#xff0c;导致使用不了&#xff0c;出现以下报错 这是因为&#xff0c;如果不用setup&#xff0c;就得使用 export default…

Flutter开发2:安装Flutter

在本篇博客中&#xff0c;我们将详细介绍如何安装Flutter开发环境。安装Flutter是开始使用Flutter进行跨平台移动应用开发的第一步。让我们开始吧&#xff01; 官方安装文档 步骤1&#xff1a;下载Flutter SDK 打开浏览器&#xff0c;访问Flutter官方网站&#xff1a;https://…

Java面向对象的三大特性

目录 封装 封装的好处&#xff1a; 权限修饰符 this 关键字 继承 使用继承的好处 什么时候用继承 ​编辑 继承的特点 注意点 super关键字 多态 多态的好处? 多态调用成员的特点 多态的弊端 封装 封装告诉我们&#xff0c;如何正确设计对象的属性和方法 简单来说…

深度学习和大数据技术的进步在自然语言处理领域的应用

文章目录 每日一句正能量前言一、深度学习在NLP中的应用二、大数据技术在NLP中的应用三、深度学习和大数据技术的影响四、应用场景后记 每日一句正能量 努力学习&#xff0c;勤奋工作&#xff0c;让青春更加光彩。 前言 随着深度学习和大数据技术的迅猛发展&#xff0c;自然语…

<Linux> 进程信号

目录 一、信号概念 二、信号的作用 三、信号的特性 四、信号捕捉初识 五、信号产生 &#xff08;一&#xff09;通过终端按键产生信号 &#xff08;二&#xff09;硬件中断 &#xff08;三&#xff09;系统调用产生信号 1. kill 函数 2. raise 函数 3. abort 函数 …

2021-10-12 51蛋骗鸡数码管前7位显示1-7第8位显示0-9

缘由 51单片机数码管问题-编程语言-CSDN问答 #include "REG52.h" sbit K1 P3^0; sbit K2 P3^1; sbit K3 P3^2; sbit K4 P3^3; bit k1,wk0; unsigned char code SmZiFu[]{63,6,91,79,102,109,125,7,127,111,128,255,64};//0-9.消隐- unsigned char Js0,miao0,fen…

数据结构—基础知识:哈夫曼树

文章目录 数据结构—基础知识&#xff1a;哈夫曼树哈夫曼树的基本概念哈夫曼树的构造算法哈夫曼树的构造过程哈夫曼算法的实现算法&#xff1a;构造哈夫曼树 数据结构—基础知识&#xff1a;哈夫曼树 哈夫曼树的基本概念 哈夫曼&#xff08;Huffman&#xff09;树又称最优树&…

T06垃圾收集器G1ZGC

垃圾收集器G1&ZGC CMS用的增量更新&#xff0c;G1用的原始快照 G1收集器&#xff08;-XX:UseG1GC&#xff09; G1(Garbage-First)是一款面向服务器的垃圾收集器&#xff0c;主要针对配置多颗处理器及大容量内存的机器&#xff0c;以极高概率满足停顿时间的要求&#xff…

Springboot集成Javamelody

JavaMelody的目标是监视QA和生产环境中的Java或Java EE应用服务器。它不是模拟用户请求的工具&#xff0c;而是根据用户对应用程序的使用情况来衡量和计算应用程序实际操作的统计信息的工具。JavaMelody主要基于请求统计和演化图。 它允许改进QA和生产中的应用程序&#xff0c…

谷歌seo搜索引擎优化需要做什么?

当你要做谷歌seo&#xff0c;经手一个你之前没有接触过的网站&#xff0c;你首先要做的就是分析网站当前的流量数据&#xff0c;如果是新站自然不需要这一步&#xff0c;不过数据分析依旧是件很重要的事情&#xff0c;做seo不懂得分析数据相当于白做 再来就是你要了解网站所在的…

【机器学习300问】21、什么是激活函数?常见激活函数都有哪些?

在我写的上一篇文章中介绍了感知机&#xff08;单个神经元&#xff09;的构成&#xff0c;其中就谈到了神经元会计算传送过来的信号的总和&#xff0c;只有当这个总和超过了某个界限值时&#xff0c;才会输出值。这也称为“神经元被激活”。如果想对神经网络是什么有更多了解的…