插入排序和希尔排序

news/2024/4/28 1:36:02

目录

一、插入排序

1.思想

2.代码实现分析

3.测试结果: 

二、希尔排序 

1.思想

2.代码实现 

3.测试 


一、插入排序

1.思想

思想:将数组分为已排序区间和未排序区间两部分,初始时,已排序区间为空,从数组的第二个元素开始,将其与已排序区间的元素进行比较,如果已排序区间的元素大于(假定要排升序)当前元素,则将已排序区间的元素后移一位,直到找到已排序区间中小于或等于当前元素的位置,将当前元素插入到该位置。然后,对数组的下一个元素进行同样的操作,直到整个数组都变为已排序区间。

接下来以一个例子来解释: 

以上面这个例子来说,假如要排升序,对于44来说,44>3,就不用交换,然后38比44小,就将44往后挪动,而3比38小,所以就不用交换了,38就在下标为1的位置,然后对于5的话,同理,应该插入到3的后面.....

2.代码实现分析

在清楚插入排序的思想后,我们来尝试实现代码。

我们需要一个变量end来表示已排序好部分的最后一个元素的下标,然后我们就可以找到下标为end+1的数是要插入的数,我们依次与已排序好的数比较,若下标为end+1的数小于下标为end的数就将下标为end的数后移,然后就应当比较前一个数了,怎么找呢?end--就可以了,然后写进循环里,直到不满足end>=0的条件就跳出循环,这样一次插入就大体完成了,一些细枝末节等会儿见代码讲解。

然后再看整体,end的取值应该在什么范围呢?很显然,end肯定从0开始,是0~n(数组大小)吗?如果是这样想的话那就错了,end应该最大是数组中倒数第二个元素,即下标为n-2。我们在前边的一次插入分析过程中也用到了end+1,如果end可以取到n-1那就会越界,这样考虑也可以得出end最多取到n-2。

上代码:

//插入排序
void InsertSort(int* arr, int n)
{int i = 0;//注意end的范围:0 <= end <= n-2for (i = 0; i < n - 1; i++){//先写一层交换,再看整体int end = i;int temp = arr[end+1]; //写外层循环里,因为每次插入都是与同一个数据比较//如果写内层循环每次比较temp都会变,因为end在不断自减while (end >= 0){//将下标为end+1的数end之前的数比较、交换//通过end--来控制比较对象,交换时将下标为end的数放在要插入数据的原位置//所以需要先用临时变量来存储要插入的数据if (arr[end] > temp){arr[end + 1] = arr[end]; //数据后移end--;}else{//arr[end+1]=temp; //不交换则说明在正确位置(end+1),将end+1处补上temp的值,跳出循环break;}}//当要插入的数据比end前边的数据都小时,会一直交换至end = -1arr[end + 1] = temp;  //与循环中else部分一致,可合并不写else中的}}

3.测试结果: 

二、希尔排序 

1.思想

希尔排序(Shell Sort)是插入排序的一种更高效的改进版本,也称为递减增量排序算法。其基本思想在于先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序

在希尔排序中,我们取一个小于n(数组大小)的整数gap(步长)作为增量,将待排序元素分成若干个子序列,所有距离为gap的倍数的记录放在同一个组中。然后,对各组内的元素进行直接插入排序。这一趟排序完成之后,每一个组的元素都是有序的。接着,我们减小gap的值,并重复执行上述的分组和排序。重复这样的操作,当gap=1时,整个数列就是有序的

简单来说,就是先按照gap分组,然后将每一组进行插入排序,这时候还是无序的,但是比原来的顺序要好一点,因为是根据gap来分组的,可以使数据更快的进行交换,最后对整体进行插入排序。我们以草图来进行具体讲解:

可以看到,共有gap组,并且每一组的下标都是按照gap递增的,然后我们再来看看按照组插入后的:

 初步排序后,比原来的有序一点,在后边排序时交换的次数会更少,效率高,所以希尔排序其实就是在插入排序基础上的优化。

关于gap:gap越大,数据跳跃的越快,小的更快的换到前边,大的更快的换到后边,但是如果gap过于大,那么会越不接近有序,因为每组排序的数据少;gap越小,数据跳跃的越慢,更接近有序,gap=1时就是插入排序。

2.代码实现 

根据上边的思想分析,先要对每一组数据进行插入排序,我们很容易知道,就是将插入排序中每一次插入稍微修改一下即可,在上面的插入排序中,我们是end--,要插入的数据是下标为end+1的数,我们改成gap即可,即end -= gap,end+gap。总共有gap组,所以很容易想到再在外面套一层循环。即下面的写法:

 然而,上面两个for循环是可以合并的,使i不断自增并满足条件i<n-gap就可以了,在两个循环中是一组一组插入交换的,而用一个循环后,则是三组交叉交换的,先是红色那组的前两个数(下标为end的数为每组的第一个数),然后是紫色那组,然后是黄色那组,end指向的数变成每组第二个数,依次进行下去(可以自己走一遍循环来观察)。

分析到这里时,大概已经清楚希尔排序了,但是gap到底应该怎么取值呢?答案是每次gap /= 2。这样到最后一次时gap正好为1,也避免了在最后单独写一遍插入排序了。

上代码:

//希尔排序
//先预排序,最后再插入排序
void ShellSort(int* arr, int n)
{int gap = n;while (gap > 1){gap /= 2;for (int i = 0; i < n - gap; i++)  //注意i<n-gap,避免越界{int end = i;int temp = arr[end + gap];while (end >= 0){if (temp < arr[end]){arr[end + gap] = arr[end];end -= gap;}else{break;}}arr[end + gap] = temp;}}}

3.测试 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

Aivis:AI语音模仿系统

Aivis&#xff1a;AI语音模仿系统。 Aivis是一个AI语音模仿系统&#xff0c;它利用深度学习和神经网络技术来模仿特定人的声音。这种系统通常涉及以下几个关键步骤和技术&#xff1a; 声音采集&#xff1a;首先&#xff0c;需要收集目标人物的声音样本。这些样本可以是录音、演…

计算机二级(Python)真题讲解每日一题:《方菱形》

描述‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬ 请写代码替换横线&#xff0…

SpringBoot集成WebService

1&#xff09;添加依赖 <dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxws</artifactId><version>3.3.4</version><exclusions><exclusion><groupId>javax.validation<…

Elastic Stack--09--ElasticsearchRestTemplate

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 spring-data-elasticsearch提供的APIQueryBuildersElasticsearchRestTemplate 方法ElasticsearchRestTemplate ---操作索引 ElasticsearchRestTemplate ---文档操作…

【Leetcode】2684. 矩阵中移动的最大次数

文章目录 题目思路代码结果 题目 题目链接&#x1f517; 给你一个下标从 0 开始、大小为 m x n 的矩阵 grid &#xff0c;矩阵由若干 正 整数组成。 你可以从矩阵第一列中的 任一 单元格出发&#xff0c;按以下方式遍历 grid &#xff1a; 从单元格 (row, col) 可以移动到 (…

K8s-CRD实战

CRD CRD的全称是CustomResourceDefinition,是Kubernetes为提高可扩展性, 让开发者去自定义资源&#xff08;如Deployment&#xff0c;StatefulSet等&#xff09;的一种方法. Controller controller是由controller-manager进行管理&#xff0c;通过API Server提供的接口实时监…