[数据结构] 基于插入的排序 插入排序希尔排序

标题:[数据结构] 排序#插入排序&希尔排序

@水墨不写bug



目录

(一)插入排序

实现思路:

插入排序实现: 

(二)希尔排序

希尔排序的基本思想: 

希尔排序的实现:


正文开始:

        排序是日常生活中常见的对数据的需求,排序有多重不同的方法,每一种方法都有各自的优缺点,本文来为你介绍两个思路类似的排序方法:插入排序和希尔排序。

(一)插入排序

       

        时间复杂度:O(N^2)

        空间复杂度:O(1)

        特点:元素越接近有序,插入排序的效率越高。

        稳定性:稳定

实现思路:

主要过程: 

        对于区间一个有序区间 [0,end] 将区间后的一个元素 nums[end+1] 插入到有序区间内。

由于nums[end+1]在移动元素时会被覆盖,需要一个临时变量tem暂时存储 nums[end+1],具体来说,将tem与nums[end]进行比较,如果

tem < nums[end]

则将end处的数据后移:

nums[end+1] = nums[end]

并将end--,继续比较。

如果

tem>=nums[end]

说明已经到达要插入的位置,直接break。

在出循环之后,将tem插入正确的位置即可:

nums[end+gap] = tem

整体实现注意事项:

        1.在实现过程中,可以先写内层循环,完成内层逻辑,再写外层循环。

        2.对于内层循环,进行循环的条件是 end>=0 ,由于外层循环end从0开始,如果内层进行循环的条件是end>0,那么如果end = 0,就无法进入循环。

        3.如何确定外层循环的区间?

        左区间从零开始;对于最大的区间,由于要将最后一个元素(size-1位置)插入到前面的区间 [0,size-2]内,所以end最大可取  size-2 。

        则区间为:

                [0,size-2](两闭区间)或者[0,size-1)(左闭右开区间)。

插入排序实现: 

#include<iostream>
#include<vector>
using namespace std;void InsertSort(vector<int>& nums)
{//外层循环,end从0开始遍历for (int i = 0; i < nums.size()-1; i++){//[0,end] end+1int end = i;int tem = nums[end + 1];//内层循环,end>=0时要进入循环while (end >= 0){if (nums[end] > tem){nums[end + 1] = nums[end];--end;}elsebreak;}nums[end + 1] = tem;}
}
void Print(vector<int> v)
{for (const auto& e : v)cout << e << " ";cout << endl;
}
int main()
{vector<int> nums = { 55,9,8,6,7,59,75,89,12,50 };Print(nums);InsertSort(nums);Print(nums);return 0;
}


(二)希尔排序

        希尔排序简单来说就是对插入排序的优化,它与插入排序的整体思路是一致的。想要写好希尔排序,就必须要讲究一个层次感,你需要明白希尔排序的几层循环到底是在干什么


希尔排序的基本思想: 

分组:

        将数组中间距为gap的数据分为一组,如图所示:(gap == 3)

可以将一组数据分为gap组:

        我们将每一组数据看做是一个小组(group),对于每一个小组,想要将他们排序,自然需要移动,由于小组内部数据相距gap,所以移动的步幅也是gap。

希尔第一层次:

        也就是插入排序内层循环的逻辑,唯一不同的是将步幅从1改为gap。

实现的操作:

        将一个数据 nums[end+gap] 插入到已经有序的区间 [0,end] 内部,并在插入后使整个区间保持有序。

        由于nums[end+gap]在移动元素时会被覆盖,需要一个临时变量tem暂时存储 nums[end+gap],具体来说,将tem与nums[end]进行比较,如果

tem < nums[end]

则将end处的数据后移:

nums[end+gap] = nums[end]

并将end-=gap,继续比较。

如果

tem>=nums[end]

说明已经到达要插入的位置,直接break。

在出循环之后,将tem插入正确的位置即可:

nums[end+gap] = tem

实现参考:

int end;
int tem = nums[end + gap];
while (end >= 0)
{if (tem < nums[end]){nums[end + gap] = nums[end];end -= gap;}elsebreak;
}
nums[end + gap] = tem;

 希尔第二层次:

        也就是插入排序外层循环的逻辑。

实现的操作:

        由于随着插入的进行,区间不断扩大,第二层次作用是不断改变区间的右端,和定位并保存需要插入的元素 nums[end+gap] 。

实现参考:

for (int i = 0; i < n - gap; i += gap)
{int end = i;int tem = nums[end + gap];while (end >= 0){if (tem < nums[end]){nums[end + gap] = nums[end];end -= gap;}elsebreak;}nums[end + gap] = tem;
}

希尔第三层次:

        前两层次实现了对一个group的排序,第三层就是要实现对所有group的排序。

实现的操作:

        外层创造循环变量j,对区间起点 i 制造偏移量:

for (int j = 0; j < gap; j++)
{for (int i = j; i < n - gap; i += gap){int end = i;int tem = nums[end + gap];while (end >= 0){if (tem < nums[end]){nums[end + gap] = nums[end];end -= gap;}elsebreak;}nums[end + gap] = tem;}
}

 希尔第四层次:

        前三层次完成了对某一特定gap下的预排序。第四层次就是要通过gap来逐渐让数组接近有序。

        gap的意义是让数据跳动的步幅增大,不同的大小的gap拥有不同的效果:

        如果gap较大,数据跳动的步幅更大,数据的移动更快,但是更不容易接近有序。

        对于较小的gap,数据步幅减小,数据移动的较慢,但是更容易接近有序;当gap取可取得的最小值1时,整个排序逻辑就会退化为插入排序。

实现的操作:

        通过特定的策略逐渐减小gap。

        经过研究,gap每次除三效果最好,但是为了避免gap小于1,于是在每次除三后再加上1,这样就是一种gap的取值策略。


void ShellSort(vector<int>& nums)
{int n = nums.size();int gap = n;while (gap > 1){gap = gap / 3 + 1;//....}
}

希尔排序的实现:


void ShellSort(vector<int>& nums)
{int n = nums.size();int gap = n;while (gap > 1){gap = gap / 3 + 1;for (int j = 0; j < gap; j++){for (int i = j; i < n - gap; i += gap){int end = i;int tem = nums[end + gap];while (end >= 0){if (tem < nums[end]){nums[end + gap] = nums[end];end -= gap;}elsebreak;}nums[end + gap] = tem;}}}
}

完~

未经作者同意禁止转载

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

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

相关文章

MybatisPlus 多数据源 @DS 选择深入源码理解原理

文章目录 MybatisPlus 多数据源 DS 选择深入源码理解原理 MybatisPlus 多数据源 DS 选择深入源码理解原理 数据源的选择&#xff0c;拦截器为DynamicDataSourceAnnotationInterceptor 这里利用了一个MethodInterceptor接口&#xff0c;我们看看&#xff0c;我们可以看到这个包…

防御笔记第四天(持续更新)

1.状态检测技术 检测数据包是否符合协议的逻辑顺序&#xff1b;检查是否是逻辑上的首包&#xff0c;只有首包才会创建会话表。 状态检测机制可以选择关闭或则开启 [USG6000V1]firewall session link-state tcp ? check Indicate link state check [USG6000V1]firewall ses…

CLion学习笔记-cmake编译和多main函数编译

这里就不讲怎么配置clion了 项目名字 pcl_kdtree_search 1.新建一个工程名字自己取&#xff0c;我这里用自己学习pcl的&#xff0c;加一个main函数&#xff0c;这个时候Cmake里边就是这样的。 #声明要求的cmake最低版本 cmake_minimum_required(VERSION 3.19) #声明一个工程…

消息称台积电下周开始试产 2nm 芯片,有望率先用于苹果 iPhone 17

消息称台积电下周开始试产 2nm 芯片&#xff0c;有望率先用于苹果 iPhone 17 &#x1f4a1;&#x1f4f1; 大家好&#xff0c;我是猫头虎&#xff0c;科技自媒体博主 &#x1f431;&#x1f42f;&#xff0c;带你洞察科技世界的每一个细节&#xff01;&#x1f525; 关于猫头…

sklearn(Python机器学习库)介绍

0 引言 Sklearn (全称 Scikit-Learn)是基于Python 编程语言的免费软件机器学习库。 Scikit-learn主要是用Python编写的,它建立在 NumPy, SciPy, Pandas 和 Matplotlib 之上,里面API 的设计非常好,所有对象的接口简单,很适合新手上路。 Scikit-learn与许多其他Python库很好地…

MAT(Eclipse Memory Analyzer) Windows安装

MAT&#xff08;Eclipse Memory Analyzer&#xff09; Windows安装 MAT&#xff08;Eclipse Memory Analyzer&#xff09;是一个Java的内存分析工具 MAT下载地址 安装完成之后的目录机构 如若出现java版本过低的解决办法 在配置文件MemoryAnalyzer.ini中添加指定Java的版本…

PD协议诱骗芯片,XSP08Q,XSP16应用笔记

XSP08Q是3C数码或小家电产品的Type-C接口控制芯片&#xff0c;它负责和PD充电器通讯&#xff0c;获取充电器的快充电压档位&#xff0c;如5V4A&#xff0c;9V3A&#xff0c;12V2A&#xff0c;15V3A&#xff0c;20V5A等等。 XSP08Q支持PD协议&#xff0c;BC1.2协议&#xff0c;Q…

从产业链视角审视工作

从产业链视角审视工作&#xff1a;定位、价值与成长 作为一名技术博客博主&#xff0c;我经常收到各种关于职业发展、技术成长和学习路径的问题。最近&#xff0c;我看了一份学习报告&#xff0c;其中提到了一种非常有趣且实用的视角——从产业链的角度去审视自己的工作。这种视…

Web 自动化测试主流框架都有哪些?

Web移动端自动化测试成为了现代软件开发流程中的重要环节&#xff0c;因此&#xff0c;很多主流框架被开发出来来帮助开发人员提高测试效率。本篇文章将从零到一详细介绍Web移动端自动化测试的主流框架。 一、Web移动端自动化测试框架简介 Web移动端自动化测试框架是一种开发工…

百元平价蓝牙耳机哪款好?平价高性价比蓝牙耳机推荐

随着蓝牙耳机的普及&#xff0c;市面上各种品牌的蓝牙耳机也层出不穷。对于那些预算在百元平价的朋友来说&#xff0c;百元平价蓝牙耳机哪款好&#xff1f;这个问题就显得格外重要了。毕竟&#xff0c;蓝牙耳机作为日常生活中不可或缺的小伙伴&#xff0c;不仅需要音质出众、续…

AD3518 SOP-8封装 单节锂电池保护芯片 可替代XB8608/XB8608A

AD3518 是一款内置 MOSFET 的单节锂电池保护芯片。该芯片具有非常低的功耗和非常低阻抗的内置 MOSFET。该芯片有充电过压&#xff0c;充电过流&#xff0c;放电过压&#xff0c;放电过流&#xff0c;过热&#xff0c;短路&#xff0c;电芯反接等各项保护等功能&#xff0c;确保…

7.深度学习概述

深度学习概述 1. 线性回归1.1 线性回归一般表达式1.2 线性回归内积表达方式&#xff1a;1.3 多个样本时&#xff0c;线性回归的进一步表达&#xff1a;1.4 线性回归方程的解析1.5 线性回归就是求loss函数的最小值 2. 如何求函数最小值2.1 一个例子2.2 求导法——求最小值2.3 求…

使用“nvm use 版本号“命令无效

使用"nvm use 版本号"命令无效 为什么无效?解决 为什么无效? 解决 将这个nodejs文件夹删除,然后在运行nvm use 版本号,则 node生效.

FastAPI 学习之路(三十四)数据库多表操作

之前我们分享的是基于单个表的数据库表的操作&#xff0c;我们在设计数据库的时候也设计了跨表&#xff0c;我们可以看下数据库的设计 class User(Base):__tablename__ "users"id Column(Integer, primary_keyTrue, indexTrue)email Column(String(10), uniqueTr…

不想成为失业大军,就要学习六西格玛?

最近&#xff0c;优思学院收到一封邮件&#xff0c;这封邮件的发送者是一位完成了我们六西格玛绿带课程的学生。 他的公司裡有20%的工程师被裁员&#xff0c;但值得注意的是&#xff0c;留下来的工程师中有70%人竟然都持有六西格玛绿带或黑带证书。 他的公司不仅希望利用这些…

el-table封装popver組件,点击列筛选行数据功能,支持筛选,搜索,排序功能

子组件&#xff1a; <template><div class"tableTool" ref"tableTool" click.stop><el-button click"shengFnc">升序</el-button><el-button click"jiangFnc">降序</el-button><el-input v-m…

安卓 APK 安装过程详解

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Android ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 1. 开机后连上网线 2. 查看网线的IP地址 3. 检查ADB连接 4. 修改文件权限 步骤 结语 我的其他博客 前言 在安卓设备上安装…

python3 ftplib乱码怎么解决

其实很简单。ftplib.FTP里面有个参数叫encoding。 如上图最后一行。所以在使用FTP时&#xff0c;主动指定编码格式即可。 ftp ftplib.FTP() ftp.encoding "utf-8" 再使用就可以了。

!vue3中defineEmits接收父组件向子组件传递方法,以及方法所需传的参数及类型定义,避免踩坑!

使用说明 1、在子组件中调用defineEmits并定义要发射给父组件的方法 const emits defineEmits([‘foldchange’]) 2、使用defineEmits会返回一个方法&#xff0c;使用一个变量emits(变量名随意)去接收 3、在子组件要触发的方法中&#xff0c;调用emits并传入发射给父组件的方法…

Kimi携手思维链,点亮论文写作之路!

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 在学术的海洋中&#xff0c;思想的火花常常在静谧的图书馆角落或深夜的电脑屏幕前迸发。今天分享的内容是一种高阶的论文写作方法&#xff1a;Kimi思维链。 Kimi&#xff0c;一个由月之…