插入排序

在待排序的元素中,假设前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. Mac M1 安装python3.6.x

    在mac M1上通过pyvenv 直接安装python3.6.x 会失败. 后来发现其实python官方直接提供了m1的pkg包,就不需要再重新编译安装了. 进入python官方为macos提供的各版 ...

  2. .NET 8 开发的跨平台多商户第三方支付SDK

    前言 快速发展的互联网应用开发中,支付功能已成为各类平台不可或缺的一环.为了帮助大家更高效地接入主流支付渠道,推荐一套基于 .NET 开发的第三方支付 SDK.该 SDK 支持跨平台运行,适用于多种操 ...

  3. vs2017试用期结束问题

    Visual Studio 2017 企业版 Enterprise 更新码:NJVYC-BMHX2-G77MM-4XJMR-6Q8QF

  4. 【多线程】Java多线程与并发编程全解析

    Java多线程与并发编程全解析 多线程编程是Java中最具挑战性的部分之一,它能够显著提升应用程序的性能和响应能力.本文将全面解析Java多线程与并发编程的核心概念.线程安全机制以及JUC工具类的使用 ...

  5. CentOS、Ubuntu安装jdk11方法

    CentOS: sudo yum install java-11-openjdk -y Ubuntu sudo apt-get install openjdk-11-jre -y 检查版本: java ...

  6. java springboot api接口导出xlsx(不使用easyexcle)

    说明 在上一个文章里说了,用了阿里巴巴的easyexcle会导致项目build后的jar包体积增大20MB左右,所以想了个曲线救国的方式 其中的\t是制表符,即tab键,\n是回车 你可以自己试着这样 ...

  7. 插件分享 | 善用 VSCode 内置的效率神器 Emmet 插件提升前端开发效率

    在 VSCode 出现之前,Emmet 插件就在前端领域玩得风生水起,当时的 Sublime Text 装上此插件,前端的编码效率那感觉就如同 2G 网络到 5G 网络的差别一般. 后来 VSCode ...

  8. AI智能体的技术架构与解决方案

    相比于传统软件,AI智能体是一个新兴事物,技术架构和解决方案仍处在高速迭代中.所以,本文章将重点放在理清AI智能体相关的技术脉络,而非具体技术实现.更多相关知识还需要读者通过第三方搜索等方式,保持与时 ...

  9. 学习CAE软件有什么方法技巧?

    在工程设计和制造领域,计算机辅助工程(CAE)软件已经成为不可或缺的工具.然而,学习使用这类复杂软件需要投入大量时间和精力.为了帮助您更快地掌握CAE软件,本文将分享一些高效的学习方法与技巧. 明确学 ...

  10. ET框架对MongoDB的使用

    一:本地测试: 1:加载DB组件 2:调整用户ID :  C2G_LoginGateHandler中创建玩家时id调整.(每次重启服务端创建小人ID是一样的,插入数据库会覆盖掉上传插入的数据) 3:在 ...