数据结构-插入排序+希尔排序+选择排序

目录

1.插入排序

插入排序的时间复杂度:

2.希尔排序

希尔排序的时间复杂度: 

3.选择排序

选择排序的时间复杂度:


所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序在生活中的作用很大,例如:某宝中的价格排行榜、销量排行榜,国内外的财富排行榜、院校排行榜等等,都是使用排序完成的。

下面我们看看常见的排序都有哪些:

1.插入排序

基本思想:

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
实际中我们玩扑克牌时,就用了插入排序的思想:

插入排序的过程如下:

假设我们有如下一个数组:

具体实现代码如下:

while (end >= 0)
{//挪数据if (tmp < a[end]){a[end + 1] = a[end];end--;}else{break;}
}
//交换数据
a[end + 1] = tmp;

tmp中存放的是3,3小于10,10往后挪一位,3小于5,5往后挪一位......当end到2时,tmp小于2,退出循环,此时5 7 10都已经往后挪了一位,数组中的元素应该是:2 5 5 7 10,我们把tmp中存放的3和2后面的5交换即可。

以上只是一个数据的插入排序,要实现整个数组的排序,我们需要对数组的每个数据都往前插入排序一下

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;}
}

插入排序的时间复杂度:

假设我们要排升序,当要排的数据刚好是降序时,时间复杂度最大,为O(N^2),因为此时排序的次数是等差数列。

当要排的数据刚好是升序的时候,是最好的情况,时间复杂度最小,但是我们在排之前并不知道数据是升序,所以至少要排N次,时间复杂度为O(N)

总结一下:

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

时间复杂度(最坏):O(N)

而我们之前学过的冒泡排序,时间复杂度是O(N^2),所以插入排序优于冒泡排序。

2.希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是先选定一个整数gap,把待排序文件中所有数据分成n/gap个组,所有距离为gap的数据分在同一组内,并对每一组内的数据进行排序,最后再进行一次gap=1的分组和排序。

希尔排序有两个过程

1. 预排序  --  使接近有序。

2. 插入排序

即先进行预排序是数据接近有序,然后使用一次插入排序,使数据有序。希尔排序实际就是对插入排序的优化。

预排序:

下面我们先来对红色组进行排序:

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

注意下标 i 不能越界,所以 i < n - gap。

以上代码只能完成对红色组的排序,下面我们来将三个组都排好序:

只需在外面再加一层循环即可。

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

这样三组数据都排好序,完成了预排序,但是上述代码有似乎还可以简化:

for (int 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 = end - gap;}else{break;}}a[end + gap] = tmp;
}

只需将i+=gap,改为i++即可,当i+=gap时,我们是将三组分开排序的,先排完红色组,再排蓝色组,最后排绿色组,而当i++时,我们是多组并排的方式,这样明显效率更高。

插入排序: 

以上就是预排序的过程,预排序完,数据变成了:1 02 3 3 4 6 5 7 9 8,还需要一次插入排序,现在我们先来思考一个问题,gap的值只能给3吗?

当然不是,gap可以任意给值,只不过,给的值不同,预排序出来的数据次序就不同。

我们可以令gap=n,gap=gap/3+1, 这样每次使用的gap都在变化,而且能确保最后一次的gap一定是1,也就确保了最后一次一定进行的是插入排序。

最终代码如下:

void ShellSort(int* a, int n)
{//gap > 1  预排序//gap = 1  直接插入排序int gap = n;while (gap > 1){gap = gap / 3 + 1;for (int 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;}}
}

希尔排序的时间复杂度: 

希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定:

《数据结构(C语言版)》--- 严蔚敏

《数据结构-用面相对象方法与C++描述》--- 殷人昆 

3.选择排序

基本思想:

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

选择排序过程如下图所示:

上图中是把待选数据遍历一遍,每次选出最小的数据放在前面,其实我们可以对其优化一下:把待选数据遍历一遍,每次同时选出最大和最小的数据,把最小的数据放在前面,最大的数据放在后面。

代码如下:

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void SelectSort(int* a, int n)
{int begin = 0;int end = n - 1;int mini = begin;int maxi = end;while (begin<end){for (int i = begin; i <= end; i++){if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]){maxi = i;}}Swap(&a[begin], &a[mini]);Swap(&a[end], &a[maxi]);begin++;end--;}
}

问题来了,上述代码对吗?

运行一下就会发现:

诶?不对啊,那到底哪里出错了呢?

下面我们举个极端的例子:

经过遍历以后发现,最大数的下标maxi和begin重合了,那我们交换时就出现问题了,最小数0确实放在了前面,但是最大数的位置也变了,下面再想把最大数放在后面,此时的下标就不能再用了,所以我们在交换a[begin]a[mini]的值后,要将最大数的下标更改:

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void SelectSort(int* a, int n)
{int begin = 0;int end = n - 1;while (begin < end){int mini = begin;int maxi = end;for (int i = begin; i <= end; i++){if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]){maxi = i;}}Swap(&a[begin], &a[mini]);//如果发生重叠,就更改下标if (begin == maxi){maxi = mini;}Swap(&a[end], &a[maxi]);begin++;end--;}
}

选择排序的时间复杂度:

选择排序的时间复杂度很简单,就是O(N^2),它每排一个数据都要遍历后面的数据一遍,遍历次数是等差数列,前面的章节中学过,等差数列的时间复杂度是O(N^2),虽然上述的代码进行优化,将遍历次数减半为N^2/2,但是量级没变,还是O(N^2)。

今天就学习这三种排序,冒泡排序、堆排序在之前的章节中已经讲解过,下节我们继续学习快速排序和归并排序,未完待续。。。

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

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

相关文章

OpenAI的多函数调用(Multiple Function Calling)简介

我在六月份写了一篇关于GPT 函数调用&#xff08;Function calling) 的博客https://blog.csdn.net/xindoo/article/details/131262670&#xff0c;其中介绍了函数调用的方法&#xff0c;但之前的函数调用&#xff0c;在一轮对话中只能调用一个函数。就在上周&#xff0c;OpenAI…

高校教师资格证备考

高等教育制度 关于人的全面发展和个体发展的关系&#xff0c;说法正确的是&#xff08;ABC&#xff09;。 A.个体发展是在全面发展基础上的选择性发展 B.全面发展是个体发展的前提和基础 C.个体发展又是全面发展的动力 D.个体发展是全面发展的前提和基础

计算机毕业设计 基于SpringBoot的车辆网位置信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

kafka入门(一):kafka消息消费

安装kafka&#xff0c;创建 topic&#xff1a; Windows安装kafka, 详情见&#xff1a;https://blog.csdn.net/sinat_32502451/article/details/133067851 Linux 安装kafka&#xff0c;详情见&#xff1a;https://blog.csdn.net/sinat_32502451/article/details/133080353 添…

[acwing周赛复盘] 第 94 场周赛20230311

[acwing周赛复盘] 第 94 场周赛20231118 总结5295. 三元组1. 题目描述2. 思路分析3. 代码实现 5296. 边的定向1. 题目描述2. 思路分析3. 代码实现 六、参考链接 总结 好久没做acw了&#xff0c;挺难的。T1 模拟T2 前缀和以及优化。T3 贪心 5295. 三元组 链接: 5295. 三元组…

Java Web——JavaScript基础

1. 引入方式 JavaScript程序不能独立运行&#xff0c;它需要被嵌入HTML中&#xff0c;然后浏览器才能执行 JavaScript 代码。 通过 script 标签将 JavaScript 代码引入到 HTML 中&#xff0c;有3种方式&#xff1a; 1.1. 内嵌式(嵌入式) 直接写在html文件里&#xff0c;用s…

Redis新操作

1.Bitmaps 1.1概述 Bitmaps可以对位进行操作&#xff0c;实际上它就是一个字符串&#xff0c;可以将Bitmaps想象为一个以位为单位的数组&#xff0c;数组中的每个元素只能存储0或者1&#xff0c;数组的下标在Bitmaps被称为偏移量。 setbit key offset value&#xff1a;设置o…

【C语言】数组下标为啥从0开始?下标越界访问一定报错吗?

本篇文章目录 0. 相关文章1. 下标从0开始问题2. 数组下标越界不报错问题 0. 相关文章 指针与指针变量数组名不是首元素地址的的2个例外拨开指针和数组名之间的迷雾 1. 下标从0开始问题 原因是&#xff1a;数组下标访问本质是“指针解引用操作”&#xff0c;而指针又是地址&am…

彩色年终工作总结汇报PPT模板下载

这是一套彩色年终工作总结汇报PPT模板&#xff0c;共27页&#xff1b; PPT模板封面&#xff0c;使用了红黄蓝色块、网格背景。中间填写年终工作总结汇报PPT标题。界面为简约商务风格。 PowerPoint模板内容页&#xff0c;由25张彩色动态幻灯片图表&#xff0c;搭配PPT文字排版…

gRPC 的原理 介绍带你从头了解gRPC

gRPC 的原理 什么是gRPC gRPC的官方介绍是&#xff1a;gRPC是一个现代的、高性能、开源的和语言无关的通用 RPC 框架&#xff0c;基于 HTTP2 协议设计&#xff0c;序列化使用PB(Protocol Buffer)&#xff0c;PB 是一种语言无关的高性能序列化框架&#xff0c;基于 HTTP2PB 保…

如何零基础自学AI人工智能

随着人工智能&#xff08;AI&#xff09;的快速发展&#xff0c;越来越多的有志之士被其强大的潜力所吸引&#xff0c;希望投身其中。然而&#xff0c;对于许多零基础的人来说&#xff0c;如何入门AI成了一个难题。本文将为你提供一份详尽的自学AI人工智能的攻略&#xff0c;帮…

Vue3-shallowRef 和 shallowReactive函数(浅层次的响应式)

Vue3-shallowRef 和 shallowReactive函数&#xff08;浅层次的响应式&#xff09; shallowRef函数 功能&#xff1a;只给基本数据类型添加响应式。如果是对象&#xff0c;则不会支持响应式&#xff0c;层成也不会创建Proxy对象。ref和shallowRef在基本数据类型上是没有区别的…