深入了解数据结构第四弹——排序(1)——插入排序和希尔排序

前言:

从本篇开始,我们就开始进入排序的学习,在结束完二叉树的学习之后,相信我们对数据在内存中的存储结构有了新的认识,今天开始,我们将进入排序的学习,今天来学习第一篇——插入排序

目录

什么是插入排序?

一、直接插入排序

1、直接插入排序的实现

2、直接插入排序的时间复杂度

二、希尔排序

1、希尔排序的实现

2、希尔排序的时间复杂度

三、直接插入排序和希尔排序时间复杂度的比较

四、总结


首先,我们先来了解一下几种排序算法都有什么,方便我们后期学习,今天,我们先来讲解插入排序

什么是插入排序?

插入排序其实挺有意思,这种排序方法在我们生活中也挺常见,例如,当我们在打扑克的时候,当我们再次摸牌时,我们会将新牌按照大小顺序插入到旧牌中

插入排序实际上就是将一个数字按照大小顺序插入到已知的序列中去

一、直接插入排序

1、直接插入排序的实现

插入排序是从后往前比较的,例如

当我们对这样一个数组进行插入排序时,我们先将1放进去,然后再放进去2与1比较,再放进去4与前面的1和2比较,以此类推,每放进去一个数字与前面数字比较,所以插入排序的过程是需要遍历数组的,我们首先可以给一个end变量标记现在排好序的数组的末端位置,再给出一个tmp变量来表示要排序的数字

插入排序的代码如下:(降序)

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

通过这段代码我们就可以看出插入排序的规则:当插入数据大于end位置的数据时,让end位置的数据向后移动一位,同时让end位置存放新插入的数据;当插入数据小于end位置数据时,那就直接让插入数据存放在end加1的位置就行

我们建立一个完整的代码示例并打印结果,给大家看看效果


//插入排序
void PrintArray(int* a, int n)
{for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");
}
void InsertSort(int* a, int n)
{for (int i = 1; i < n; i++){int end = i - 1;int tmp = a[i];while (end >= 0){if (tmp > a[end]){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = tmp;}
}void TestInsertSort()
{int a[] = { 1,2,4,7,8,2,5,3 };PrintArray(a, sizeof(a) / sizeof(a[0]));InsertSort(a, sizeof(a) / sizeof(a[0]));PrintArray(a, sizeof(a) / sizeof(a[0]));
}
int main()
{TestInsertSort();return 0;
}

运行结果:

第一行是排序前,第二行是排序后

2、直接插入排序的时间复杂度

时间复杂度最坏O(N^2)
时间复杂度最好O(N)

如图所示:

不同的两组数据在用直接插入排序降序时,左边时间复杂度明显小于右边

综上,其实综合来说直接插入排序的时间复杂度是介于O(N)O(N^2)之间的

二、希尔排序

1、希尔排序的实现

希尔排序是插入排序的改进,它通过将待排序的数据分割成若干个子序列来提高插入排序的效率。希尔排序的基本思想是:先将整个待排序的序列分割成若干个子序列,然后对这些子序列分别进行插入排序,最后再对整个序列进行一次插入排序。

希尔排序的具体步骤如下:

  1. 选择一个增量序列,通常是按照一定规则递减的序列,最常用的是取增量序列为n/2,n/4,n/8...1,后来经过改进,一般选择n/3+1来确保程序的稳定性
  2. 根据增量序列的值,将待排序序列分割成若干个子序列,对每个子序列进行插入排序。
  3. 逐渐缩小增量,重复第2步,直到增量为1。
  4. 最后对整个序列进行一次插入排序

例如:对于{9,8,7,6,5,4,3,2,1,0}这样一组数据,用希尔排序排升序的步骤如下:

实现上图功能的代码如下:

void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){gap = gap / 3 + 1;    //+1可以保证最后一次一定为1for (int i = 0; i < n - gap; i++)      //每组插入排序{int end = i;int tmp = a[end + gap];while (end >= 0){if (a[end] > tmp){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}

这个过程跟插入排序相似度很高,可以将两者放在一起比较体会一下

希尔排序的完整代码示例:

void PrintArray(int* a, int n)
{for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");
}
void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){gap = gap / 3 + 1;    //+1可以保证最后一次一定为1for (int i = 0; i < n - gap; i++)      //每组插入排序{int end = i;int tmp = a[end + gap];while (end >= 0){if (a[end] > tmp){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}
void TestShell()
{int a[] = { 9,8,7,6,5,4,3,2,1,0 };printf("排序前:");PrintArray(a, sizeof(a) / sizeof(0));ShellSort(a, sizeof(a) / sizeof(0));printf("排序后:");PrintArray(a, sizeof(a) / sizeof(0));
}
int main()
{TestShell();return 0;
}

运行结果:

2、希尔排序的时间复杂度

希尔排序的时间复杂度取决于增量序列的选择,一般情况下,希尔排序的时间复杂度为O(n log n)到O(n^2)之间。希尔排序是不稳定的排序算法,因为在排序过程中会改变相同元素之间的相对位置,所以希尔排序的时间复杂度其实并不能真正的计算出来,但希尔排序仍然要比直接排序要高效的多,我们可以通过一些方式来检验这种高效性

三、直接插入排序和希尔排序时间复杂度的比较

我们可以通过clock()函数来检验他们两个的时间复杂度

void TestOP()
{srand(time(0));const int N = 10000;int* a1 = (int*)malloc(sizeof(int) * N);int* a2 = (int*)malloc(sizeof(int) * N);int* a3 = (int*)malloc(sizeof(int) * N);for (int i = 0; i < N; i++)       //让这两个算法都处理一万组数据,比较他们两个用时长短{a1[i] = rand();a2[i] = a1[i];a3[i] = a1[i];}int begin1 = clock();  InsertSort(a1, N);int end1 = clock();int begin2 = clock();ShellSort(a2, N);int end2 = clock();printf("InsertSort:%d\n", end1 - begin1);  //直接插入排序所用时间printf("ShellSort:%d\n", end2 - begin2);   //希尔排序所用时间
}

运行结果:

四、总结

通过运行结果我们可以明显的观察到,在处理相同大小的一组数据时,希尔排序比直接插入排序要高效的多,且随着数据的增多,这种差异会愈加明显

以上就是插入排序的全部内容,鉴于篇幅问题,本篇文章讲解的有些粗糙,如果有不理解的地方,欢迎与我私信交流或者在评论区中指出!!!

感谢观看,创作不易,还请各位大佬点赞支持!!!

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

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

相关文章

回溯算法中常见的使用方法逻辑整理

回溯算法 常见的使用方法逻辑整理 1. 回溯算法 特点 回溯算法实际上一个类似枚举的搜索尝试过程&#xff0c;主要是在搜索尝试过程中寻找问题的解&#xff0c;当发现已不满足求解条件时&#xff0c;就“回溯”返回&#xff0c;尝试别的路径。回溯法是一种选优搜索法&#xff0…

CentOS 7安装Nginx

说明&#xff1a;本文介绍如何在CentOS 7操作系统中安装Nginx 下载安装 首先&#xff0c;去官网上下载Nginx压缩包&#xff0c;官网地址&#xff1a;https://nginx.org/en/download.html&#xff0c;我这里下载稳定版1.24.0&#xff1b; 上传到云服务器上&#xff0c;解压&am…

Vue入门:天不生Vue,前端万古如长夜 - Vue从入门到放弃

目录 &#x1f44b; Vue环境搭建 1.安装node.js 2.配置环境变量 3.VSCode配置 4.安装Vue CLI 5.在VS Code中打开Vue项目 6.运行Vue项目 &#x1f440; Vue基础学习 1.引入vue.js 2.数据方法 3.生命周期&#xff01; 4.模板语法 5.对象语法 6.条件渲染 7.列表渲…

openstack安装dashboard后登录网页显示404错误

1. 2.进入该目录vim /etc/httpd/conf.d/openstack-dashboard.conf 增加这一行 WSGIApplicationGroup %{GLOBAL} 重启httpd后就可以访问了

Oracle 19c RAC 补丁升级 补丁回退

补丁升级流程 补丁升级 停止集群备份家目录 两节点分别操作 cd /u01/app/19.3.0/grid/bin/ crsctl stop crs tar -zcvf /u01/app.tar.gz /u01/app /u01/app/19.0.0/grid/bin/crsctl start crs 两节点OPatch替换 --- 表示 root 用户&#xff0c;$ 表示 Oracle 用户提示符&#…

QT、ffmpeg视频监控分屏

1、支持分屏&#xff08;4&#xff0c;6&#xff0c;8&#xff0c;9&#xff0c;13&#xff0c;16&#xff0c;25&#xff0c;32&#xff0c;64&#xff09;切换 2、支持拖拽效果 3、支持播放mp4&#xff0c;rtmp等 4、本人亲测支持播放32路&#xff0c;64路没做测试 5、支持读…

计算机网络—传输层UDP协议:原理、应用

​ &#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;2月のセプテンバー 1:21━━━━━━️&#x1f49f;──────── 5:21 &#x1f504; ◀️ ⏸ ▶️ ☰ &am…

Github 2024-04-15 开源项目日报Top10

根据Github Trendings的统计,今日(2024-04-15统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目4TypeScript项目2HTML项目1JavaScript项目1C++项目1Rust项目1Mojo项目1Fooocus: 图像生成软件 创建周期:188 天开发语言:Python协议…

基于SSM微信小程序的四六级词汇系统

采用技术 基于SSM微信小程序的四六级词汇系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringMVCMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 用户客户端 注册用户界面 首页界面 我的界面 用户信息界…

SqlServer专题

目录 1&#xff0c;连接数据库 2&#xff0c;连接池 1.何为连接池&#xff1f; 2.连接池运行原理。 3.如何查看连接池&#xff1f; 4.连接池注意事项。 3&#xff0c;一般SQL语句。 4&#xff0c;控制语句 1.判断语句 2.循环语句 5&#xff0c;视图 1.使用…

Spark 应用程序优化和调优总结

文章目录 前言调整 Spark 默认配置查看和设置 Spark 配置信息动态扩展集群负载 数据的缓存和持久化DataFrame.cache()DataFrame.persist()何时缓存和持久化何时不缓存和持久化 Spark 中的 JOINs广播连接排序合并连接 总结 前言 本文总结了 Spark 中比较重要和常用的调优手段&a…

RedisTemplate

3.3.RedisTemplate 在Sentinel集群监管下的Redis主从集群&#xff0c;其节点会因为自动故障转移而发生变化&#xff0c;Redis的客户端必须感知这种变化&#xff0c;及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。 下面&#xff0c;我们…