【排序】插入排序,希尔排序

前面我们讲述了冒泡排序和选择排序,我们本章讲的排序方法是插入排序,插入排序是希尔排序实现的基础函数,大家一定要好好理解插入排序的逻辑,这样才能在后面学习希尔排序的时候,更容易的去理解,我们直接开始。

目录

插入排序(以升序为例)

基本思想:

思路

代码实现:

总结

希尔排序

基本思想:

一组一组依次排序代码实现

多组同时排序

希尔排序的时间复杂度分析

总结

总结


插入排序(以升序为例)

基本思想:

直接插入排序是一种简单的插入排序法,其基本思想是:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

就和我们打牌时,从小到大排牌序,当拿到一张新牌时,我们从后往前找,当最后的牌大于此时的牌,那么就让最后一张牌向后挪动一位,继续和倒数第二张比较,若倒数第二张小于此时的牌,就说明找到了位置,将此时的牌插入即可。

如上图中,此时的牌为7,那么我们从后往前找,发现10>7,那么10就往后挪动,继续向前找,发现是5,而5<7,说明找到了合适的位置将7放入5的后面即完成了插入排序。

思路

当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移

由于插入排序插入第i个元素时,需要前i-1个元素都是有序的,因此我们仍然需要从第1个元素开始排序

假设我们目前前i个是有序的,我们排序的就是第i+1个元素,我们用tmp记录a[i+1]的值,然后从后往前开始依次比较,由下标i到下标0,我们再创建循环,用变量(j=i , j >= 0 , j - -)控制循环

当 a[j] > tmp时,a[j]就向后挪动,即a[j+1] = a[ j ]  

当a[j] < tmp 时,说明已经找到了合适的位置,直接跳出循环,并将j+1的位置赋值为tmp即可

以下便是逻辑图: 

以上是找到比tmp小正常插入的情况 ,还有一种情况,当数组在tmp前内没有比tmp小的元素时,那么就会将小数放到数组首位,逻辑图如下,还是上面数组的例子。

动态逻辑图

代码实现:

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

小结

直接插入排序的特性总结:
1. 元素集合越接近有序,直接插入排序算法的时间效率越高
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1),它是一种稳定的排序算法
4. 稳定性:稳定

希尔排序

希尔排序法又称缩小增量法。希尔排序已经算是是排序中的大哥了,所以也比较难以理解,他是与快速排序,堆排序,归并排序在同一条赛道上的排序算法,十分的厉害。

基本思想:

希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

可能比较难理解,希尔排序分为两个部分,首先进行预排序,再进行插入排序

预排序:跨元素进行分组排序,让数组更接近有序,这样再进行插入排序的时候,基本都是在有序的情况下,那么再进行插入排序就减少了数组挪动的次数,效率更高了。

我们假设跳的距离为gap,gap初始值为3

看一下逻辑图,我们就明白进行预排序后的效果

下面我们来单独实现代码,我们可以将代码拆分成几个小部分,依次实现,这样会让代码实现变得更加容易实现,这便是由小及大的思想

我们先来实现对单个分组排序的实现,即对红色排序的实现

代码实现的底层逻辑,依然是插入排序,只不过在进行遍历和比较的时候是一次跳跃gap个元素

大家看一下代码实现应该就能理解

部分代码实现

int gap = 3;
for (size_t i = 0; i < n - gap; i+=gap)
{int tmp = a[i + gap];int j = 0;for (j = i; j >= 0; j-= gap){if (a[j] > tmp){a[j + 1] = a[j];}else{break;}}a[j + gap] = tmp;
}

在完成单趟逻辑后,然后我们再建一个for循环,让gap组依次进行排序,即完成了一组一组依次排序的逻辑实现

一组一组依次排序代码实现

	int gap = 3;for (int k = 0; k < gap; k++){for (size_t i = k; i < n - gap; i += gap){int tmp = a[i + gap];int j = 0;for (j = i; j >= 0; j -= gap){if (a[j] > tmp){a[j + 1] = a[j];}else{break;}}a[j + gap] = tmp;}}

还有一种实现方法,是令多组同时进行排序,只需要修改一下逻辑代码即可

多组同时排序

int gap = 3;
for (size_t i = 0 ; i < n - gap; i++)
{int tmp = a[i + gap];int j = 0;for (j = i; j >= 0; j -= gap){if (a[j] > tmp){a[j + 1] = a[j];}else{break;}}a[j + gap] = tmp;
}

二者的逻辑图如图所示

希尔排序的时间复杂度分析

希尔排序的时间复杂度比较难计算,因为gap的取值方法很多,导致很难去计算

我们通过上面的逻辑分析,发现 在预排序阶段

gap越大,大的数可以更快的跳到后面,小的数可以更快的跳到前面,越不接近有序

gap越小,大的数跳到后面越慢,小的数跳到前面越慢,但越接近有序

因此控制gap的大小是增加效率的直接办法

但是如何取最适合的gap呢,根据大量数据统计,我们发现当gap = n/3时效率最高,但是我们需要+1,保证gap最后等于1

代码如下

void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){// +1保证最后一个gap一定是1// gap > 1时是预排序// gap == 1时是插入排序gap = gap / 3 + 1;for (size_t i = 0; i < n - gap; ++i){int end = i;int tmp = a[end + gap];while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}

我们以n/3为例,以gap对时间复杂度的影响进行分析

如下

 代码实现

void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){// +1保证最后一个gap一定是1// gap > 1时是预排序// gap == 1时是插入排序gap = gap / 3 + 1;for (size_t i = 0; i < n - gap; ++i){int end = i;int tmp = a[end + gap];while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}

小结

1. 希尔排序是对直接插入排序的优化。


2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。


3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定,通过数据统计,希尔排序的时间复杂度大概为O(n^1.3)

4. 稳定性:不稳定

总结

以上是对插入排序和希尔排序的分析,是一种新的排序思想,其中的种种知识点也很碎很多,希望大家能够有所收获。

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

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

相关文章

关于无法通过脚本启动Kafka集群的解决办法

启动Kafka集群时&#xff0c;需要在每台个节点上启动启动服务&#xff0c;比较麻烦&#xff0c;通过写了以下脚本来进行启停&#xff1b;发现能正常使用停止功能&#xff0c;不能正常启动Kafka&#xff1b; Kafka启停脚本&#xff1a; ## 以防不能通过shell脚本启动Kafka服务…

C盘扩容——只能删除C盘右边的磁盘对C盘进行扩展

winR弹出命令框 输入&#xff1a;compmgmt.msc 进入磁盘管理页面 注意&#xff1a;被删除盘如果有重要数据信息&#xff0c;请备份。 或者删除之前转移至其他盘&#xff0c;否则删除之后&#xff0c;则无法找回。 尤其是安装的软件。 规范安装目录十分重要。 将C盘右边的磁盘&a…

安防综合管理系统EasyCVR视频汇聚平台GA/T 1400协议中的关键消息交互示例

在当今的信息化时代&#xff0c;公共安全防范日益成为保障社会和谐稳定的关键。视频监控系统作为现代安全防范的重要手段&#xff0c;正不断在公安、交通、城市管理等领域发挥着越来越重要的作用。而GA/T 1400协议视图库&#xff0c;作为公安视频图像信息应用系统的标准&#x…

健身日记之倒立俯卧撑学习——起始日2024.6.4

文章目录 前言 自我介绍 昔日计划 新目标计划 瓶颈突破尝试 参考视频及文章 前言 有轻微健身基础&#xff0c;正式接触街健五大神技&#xff0c;立志在两年内解锁全部&#xff0c;将有机会的进行日常训练和目标肌群锻炼&#xff0c;这里向大家展示我的计划和安排&#xf…

opencv-python(五)

opencv的颜色通道中顺序是B&#xff0c;G&#xff0c;R。 图像属性 import cv2img cv2.imread(jk.jpg) print(fshape{img.shape}) print(fsize{img.size}) print(fdtype{img.dtype}) shape&#xff1a;图像像素的行&#xff0c;列&#xff0c;通道 size&#xff1a;行数 X …

YonSuite收款通,助力企业618更快收款

随着电商节日“618”的临近&#xff0c;各大企业纷纷摩拳擦掌&#xff0c;准备在这场年中大促中大展身手。然而&#xff0c;随着销售额的激增&#xff0c;收款管理问题也愈发凸显&#xff0c;成为制约企业快速发展的重要瓶颈。在这个关键时刻&#xff0c;YonSuite收款通凭借其卓…

echarts图例formatter配置添加百分比

echarts图例如何添加百分比 const pieChart async () > {const myChart echarts.init(piepic.value)const piedata await getPieData(); // 等待数据返回myChart.setOption({title: {},grid: {},tooltip: {trigger: item,},legend: {top: middle,align:left,icon: circl…

电源小白入门学习10——浪涌、防浪涌器件、浪涌保护芯片

浪涌、防浪涌器件、浪涌保护芯片 浪涌浪涌保护器件的分类与原理保险丝TVS二极管新防护电路 浪涌 浪涌&#xff0c;相信不少学习过电子的同学或多或少都通过这个词&#xff0c;但是到底什么是浪涌呢&#xff0c;GPT给我的答案是这样的&#xff1a; 浪涌&#xff0c;也称为瞬态…

【深度学习】【机器学习】支持向量机,网络入侵检测,KDD数据集

文章目录 环境加载数据归一化数据训练模型用测试数据集给出评估指标准确率召回率预测某个输入数据随便取一行数据加载训练好的SVM支持向量机模型并预测 全部数据和代码下载 环境 之前介绍过用深度学习做入侵检测&#xff0c;这篇用向量机。 环境Python3.10 requirements.txt…

【miniconda】安装miniconda

☆ 问题描述 ubuntu环境下安装miniconda ★ 解决方案 ubuntu环境下安装miniconda 下载miniconda 包 miniconda官网地址&#xff1a;https://docs.conda.io/en/latest/miniconda.html 清华大学镜像地址&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/anaconda/minicon…

超级加速器链接促进会(UALink)能否打破英伟达的垄断?

近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术的飞速发展催生了对高性能计算和数据中心互联技术的巨大需求。然而&#xff0c;随着市场的集中化&#xff0c;英伟达凭借其专有的NVLink和InfiniBand技术&#xff0c;几乎垄断了这一市场。这种局面引起了其他科技巨头…

MFC实现子控件focus焦点上下移动父控件ListView和Gridview也跟着向上下移动

项目中要实现mfc功能&#xff0c;然后子空间焦点下移&#xff0c;LIstView和Gridview父空间不会下移&#xff0c;所以就有这个文章。废话不多说直接上代码。 MFCGridView.java import android.content.Context; import android.util.AttributeSet; import android.view.View;…

白酒:产地的酿酒历史与文化遗产

云仓酒庄豪迈白酒作为中国酿酒工艺的品牌之一&#xff0c;其产地的酿酒历史与文化遗产具有深远的意义和价值。产地酿酒历史悠久&#xff0c;代代相传的酿酒技艺和与众不同的文化传统&#xff0c;构成了云仓酒庄豪迈白酒与众不同的品质和风味。 据云仓酒庄豪迈介绍&#xff0c;中…

力扣----轮转数组

题目链接&#xff1a;189. 轮转数组 - 力扣&#xff08;LeetCode&#xff09; 思路一 我们可以在进行每次轮转的时候&#xff0c;先将数组的最后一个数据的值存储起来&#xff0c;接着将数组中前n-1个数据依次向后移&#xff0c;最后将存储起来的值赋给数组中的第一个数据。 …

Pixi绘制地图和小车

之前已经用Pixi绘制出了各种图形以及通过图片绘制精灵&#xff0c;这节用pixi绘制网格地图&#xff0c;并通过图片制作一个Sprite&#xff0c;让这个Sprite在网格地图上运动。首先需要在页面中添加一个div用来后期展示canvas的画布&#xff0c;并将此div实例化为PIXI的Applicat…

企业转型必上的监控系统智能管家大屏UI前端开发

企业转型必上的监控系统智能管家大屏UI前端开发

Istio安装记录

环境介绍 我使用的是k8s 1.23.3版本 istio使用的是istio-1.13.3-linux-amd64.tar.gz 把文件下载k8s集群下&#xff0c;解压 tar -vzxf istio-1.13.3-linux-amd64.tar.gz然后设置环境变量 [rootmaster istio]# cat /etc/profile export ISTIO_HOME/root/istio-1.13.3 expor…

3067. 在带权树网络中统计可连接服务器对数目 Medium

给你一棵无根带权树&#xff0c;树中总共有 n 个节点&#xff0c;分别表示 n 个服务器&#xff0c;服务器从 0 到 n - 1 编号。同时给你一个数组 edges &#xff0c;其中 edges[i] [ai, bi, weighti] 表示节点 ai 和 bi 之间有一条双向边&#xff0c;边的权值为 weighti 。再给…

Yolo-v5模型训练速度,与GeForce的AI算力描述

1.GeForce RTX3070 Ti官网参数&#xff1a; GeForce RTXTM 3070 Ti 和 RTX 3070 显卡采用第 2 代 NVIDIA RTX 架构 - NVIDIA Ampere 架构。该系列产品搭载专用的第 2 代 RT Core &#xff0c;第 3 代 Tensor Core、全新的 SM 多单元流处理器以及高速显存&#xff0c;助您在高性…

【网络安全的神秘世界】MySQL

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 MySQL MySQL 教程 | 菜鸟教程 (runoob.com) 什么是数据库 数据库&#xff08;Database&#xff09;是按照数据结构来组织、存储和管理数据的仓库 在do…