插入排序

在待排序的元素中,假设前k个元素已有序,现将第k+1个元素插入到前面已经排好的序列中,使得前k个元素有序。

按照此法对所有元素进行插入,直到整个序列有序。

但我们并不能确定待排元素中究竟哪一部分是有序的。

所以我们一开始只能认为第一个元素是有序的依次将其后面的元素插入到这个有序序列中来,直到整个序列有序为止。



↑↑↑黑色圈住的数字表示要插入到前面序列的数字


希尔排序

讲完插入排序,就该讲我们的重点了。

希尔排序是一种改进的插入排序算法,也被称为缩小增量排序。

它通过将待排序序列分割成多个子序列来进行排序,然后逐步缩小子序列的长度,最终使整个序列变为有序。

希尔排序的核心思想是将相距某个增量的元素组成一个子序列,对子序列进行插入排序。

然后逐步减小增量,重复上述过程,直到增量为1时,完成最后一次插入排序,使整个序列成为有序的。


希尔排序的优点

  1. 效率较高:对于大规模数据集,希尔排序通常比简单插入排序更快,特别是在处理近乎有序的数据时,由于跳跃式的比较和交换,效率提升显著。

  2. 灵活性:希尔排序通过调整间隔序列来适应不同类型的数据分布,这使得它在某些情况下能获得更好的性能,尽管没有一种固定的间隔序列适合所有场景。

  3. 稳定性:虽然希尔排序本质上不是稳定的排序算法,但在某些实现版本中,如果对相等元素进行特殊处理,可以保持相对位置不变,表现为某种形式的稳定性。

  4. 易于理解:作为一种改进的插入排序,希尔排序的原理相对直观,容易学习和实现。

然而,希尔排序的主要缺点在于它的时间复杂度依赖于所选的间隔序列,不稳定性和最坏情况下的效率不高可能会限制它在一些高并发环境下的使用。

因此,在实际应用中需要权衡性能和代码实现复杂性。


时间复杂度

希尔排序的时间复杂度取决于增量序列的选取, 一般最好情况下为O(nlogn),最坏情况下为O(n^2)。

希尔排序是 不稳定的排序算法 ,即可能改变相同元素的原始顺序。


希尔排序的思想

希尔排序也被称为缩小增量排序。

其基本思想是将待排序的元素按照一定的间隔分组,对每组使用插入排序算法进行排序,

然后逐步缩小间隔,再进行排序,直至间隔为1时进行最后一次排序。(如图)



在希尔排序中,我们要引入gap(间隔):



当gap不为1时,我们可以把它看做为一个预排序,先把数组变得比较有序。

然后当 gap为1时 就是直接 插入排序了。

因为插入排序对比较有序的数组排列效率更高,所以希尔排序就为先预排序,再直接插入排序。

预排序

我们先定义一个长度为5的逆序数组{5,4,3,2,1},再来假设gap为3。

知周所众 众所周知插入排序再排逆序的数组时,时间复杂度为最坏的情况。 所以我们才要进行预排序

经过预排序后数组,已经变得比较有序了,这对后面的直接插入排序是有好处的提高效率


Knuth增量序列

Knuth增量序列是希尔排序中使用的一种增量序列,它可以保证gap最后一定为1,

它的计算方式为:

gap = 1, 3, 9, 27, ...

其中gap的初始值为1,然后每次计算下一个增量值h时,都乘以3再加1,直到h大于等于数组长度的三分之一

Knuth增量序列的特点是在每次排序中能够更好地减少逆序对的数量,从而提高排序的效率。

该增量序列的选择是经验性的,并没有严格的数学证明,但在实践中已经被广泛接受,并被证实在大多数情况下都能够有效地改善希尔排序的性能


代码实现希尔排序

下面是使用实现希尔排序的代码:

#include<iostream>
using namespace std;
const int N = 1e6+5;
int n,arr[N];
void shellSort() {
int gap = 1;// 使用Knuth增量序列,gap = 1, 3, 9, 27, ...
while (gap < n/3) gap = 3 * gap + 1;// 使用Knuth增量序列,保证gap最后为1
while (gap >= 1) {// 逐步缩小增量直到1
// 对每个子序列进行插入排序
for (int i = gap; i < n; i++)
for (int j = i; j >= gap && arr[j] < arr[j-gap]; j -= gap) swap(arr[j], arr[j-gap]);
gap /= 3;// 缩小增量
}
}
int main() {
cin>> n;
for(int i=0;i<n;i++) cin>> arr[i];
shellSort();// 排序
// 输出
for (int i = 0; i < n; i++) cout << arr[i] << " ";
return 0;
}

该代码使用了Knuth增量序列,h的初始值为数组长度的一半,然后逐渐减小h的值。

在每次循环内部,对每个子序列使用插入排序算法进行排序。最后输出排序后的数组。


总的来说,希尔排序可以应用于各种排序问题,并且在大规模数据下具有较好的性能。

【C++】神秘-希尔排序的更多相关文章

  1. 算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)

    本篇博客中的代码实现依然采用Swift3.0来实现.在前几篇博客连续的介绍了关于查找的相关内容, 大约包括线性数据结构的顺序查找.折半查找.插值查找.Fibonacci查找,还包括数结构的二叉排序树以 ...

  2. 希尔排序(java)

    时间复杂度为O( n^(3/2) )不是一个稳定的排序算法 如何看一个算法是否稳定:{("scala",12),("python",34),("c++ ...

  3. Html5 希尔排序演示

    希尔排序(Shell Sort)是插入排序的一种.也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本. 如下图所示: 代码如下: <!DOCTYPE html> <html& ...

  4. 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析之后续补充说明(有图有真相)

    如果你觉得我的有些话有点唐突,你不理解可以想看看前一篇<C++之冒泡排序.希尔排序.快速排序.插入排序.堆排序.基数排序性能对比分析>. 这几天闲着没事就写了一篇<C++之冒泡排序. ...

  5. 希尔排序及希尔排序java代码

    原文链接:http://www.orlion.ga/193/ 由上图可看到希尔排序先约定一个间隔(图中是4),然后对0.4.8这个三个位置的数据进行插入排序,然后向右移一位对位置1.5.9进行插入排序 ...

  6. 冒泡排序 & 选择排序 & 插入排序 & 希尔排序 JavaScript 实现

    之前用 JavaScript 写过 快速排序 和 归并排序,本文聊聊四个基础排序算法.(本文默认排序结果都是从小到大) 冒泡排序 冒泡排序每次循环结束会将最大的元素 "冒泡" 到最 ...

  7. 希尔排序(Shell)

    希尔排序的实质就是分组插入排序,该方法又称缩小增量排序. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序, ...

  8. 希尔排序(c++)

    希尔排序(Shell Sort)是插入排序的一种.也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本.希尔排序是非稳定排序算法.该方法因DL.Shell于1959年提出而得名. 希尔排序是把记 ...

  9. JavaScript排序算法——希尔排序

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. IOS- 快速排序,冒泡排序,直接插入排序和折半插入排序,希尔排序,堆排序,直接选择排序

    /*******************************快速排序 start**********************************///随即取 当前取第一个,首先找到第一个的位置 ...

随机推荐

  1. 私有资产测绘&安全流水线Shovel

    私有资产测绘&安全流水线Shovel(Preview)发布 发布版本:Shovel-v0.1.7 当前项目发布版本 Shovel-v0.1.7(预览版) | 企业级资产测绘管理,开启资配漏补新 ...

  2. C# 基础问题汇集

    (1)new List并不是null,可以正常的被遍历和AddRange class Program { public static void Main() { //var t = new test( ...

  3. numpy.tile用法

    先说下在numpy中,个人对array的维度的比较形象的理解: array的维度就是从最外边的[]出发(可理解为array的声明),一直找到具体数值而经过的[]的数量(含最后的数值,它是最后一维) 比 ...

  4. 用鼠标画圆点(java GUI)

    话不多说,先看效果 当然你也可以发挥脑洞绘制更更棒的 源码如下: package javaBasic; import java.awt.*; import java.awt.event.*; impo ...

  5. 解决DevToolsActivePort file doesn't exist

    今天遇到个小问题:selenium 启动 chrome crash,报错:DevToolsActivePort file doesn't exist. 在option中添加一下几行: option = ...

  6. Python中的cls变量

    技术背景 在Python的类型设计中,有时候会遇到一个cls参数.其实cls参数就是一个约定俗成的名称,用其他的名字也能正常运行但不建议这么用.它的作用类似于实例方法中的self参数,代表的是类本身, ...

  7. AtCoder Beginner Contest 408 E-F 题解

    E. Minimum OR Path 题意 给你一个 \(N\) 个点 \(M\) 条边的无自环的无向图,第 \(i\) 条边连接 \(u_i\) 和 \(v_i\),权值为 \(w_i\). 在所有 ...

  8. 国内用什么邮箱比较正式 个人邮箱对比qq邮箱网易新浪搜狐阿里云

    本文永久链接:https://forum.piwind.com/d/19-guo-nei-yong-shi-yao-you-xiang-bi-jiao-zheng-shi-ge-ren-you-xia ...

  9. Golang协程和线程区别

    一.进程.线程.协程介绍 进程:系统中所有的应用程序都是以进程(process)的方式运行,是系统进行资源分配和调度的基本单位,每个进程都有自己的独立的地址空间,使得进程之间的地址空间相互隔离. 线程 ...

  10. 具有mDNS功能的串口服务器

    1.概述: 通过mDNS协议可以获得设备的ID.mac.IP.port等信息,方便计算机在同一个局域网内连接到具有该服务的模块.支持产品有串口服务器.串口转以太网模块.RS485串口转网口芯片等. 图 ...