排序算法(六)——希尔排序

2023-11-12

基本思想

希尔排序是基于插入排序的,又叫缩小增量排序。

在插入排序中,标记符左边的元素是有序的,右边的是没有排过序的,这个算法取出标记符所指向的数据,存入一个临时变量,接着,在左边有序的数组中找到临时变量应该插入的位置,然后将插入位置之后的元素依次后移一位,最后插入临时变量中的数据。

试想,假如有一个很小的数据项在靠近右端的位置上,把这个数据项插入到有序数组中时,将会有大量的中间数据项需要右移一位,这个步骤对每一个数据项都执行了将近N次复制。虽然不是所有数据项都必须移动N个位置,但是,数据项平均移动了N/2个位置,一共N个元素,总共是N2/2次复制,这实际上是一个很耗时的过程,希尔排序就是对这一步骤进行了改进,不必一个个的移动所有中间数据项,就能把较小的数据项移动到左边,大大提高了排序效率。

希尔排序通过加大插入排序时元素之间的间隔,并对这些间隔的元素进行插入排序,从而使数据能大跨度地移动。数据项之间的间隔被称为增量,习惯上还用h表示。

下图表示的是增量为4时对10个数据项进行第一轮希尔排序的过程:

在这里插入图片描述
此时,数据已经基本有序,所有元素离它在最终有序序列中的位置相差都不超过2个单元,通过创建这种交错的内部有序的数据项集合,把完成排序所需的工作量降到了最小,这也是希尔排序的精髓所在。

在用java实现希尔排序之前,还有一个问题需要弄清楚,就是这个增量该怎么选择?

最简单的方法是第一轮排序的间隔为N/2,第二趟排序的间隔为N/4,依次类推。但是,实践证明,这种方法有时会使运行时间降到O(N2),并不比插入排序的效率更高。

保持间隔序列中的数字互质很重要,也就是说,除了1之外它们没有公约数。简单地取间隔为N/2,N/4,N/8…1时,没有遵循这一约束,所以使希尔排序的效率降低。

有很多种有效地生成间隔序列的方法,本文提供一种,下一节的java代码也是按照这种方法来生成间隔序列的。

这种序列生成方法是由Donald Knuth(可以百度一下,图灵奖获得者,一位计算机领域的大牛)提出来的。

数列以逆向的形式从1开始,通过递归表达式:

h=3*h+1

来产生后面的间隔。

比如,我们有1000个数据项需要排序,利用h=3*h+1产生的间隔序列为:1,4,13,40,12,121,364,1093,3280…

第八个数1093显然超出了要排序的元素总数,所以第一轮排序,应该选取的间隔为364,第二轮为121,第三轮为12……

java实现

//希尔排序
      public void shellSort(){
            
             int len = array.length;
             int counter = 1;
            
             int h = 1;
             while(3*h+1<len){  //确定第一轮排序时的间隔
                    h = 3*h+1;
             }
            
             while(h>0){
                    for(int i=0;i<h;i++){ 
                           shellInsertSort(i,h);  //对间隔为h的元素进行插入排序
                    }
                   
                    h = (h-1)/3;  //下一轮排序的间隔
                   
                    System.out.print("第"+counter+"轮排序结果:");
                    display();
                    counter++;
             }
            
      }
     
      /**
       * 希尔排序内部使用的插入排序:
       * 需要进行插入排序的元素为array[beginIndex]、array[beginIndex+increment]、array[beginIndex+2*increment]...
       *@param beginIndex 起始下标
       *@param increment 增量
       */
      private void shellInsertSort(int beginIndex,int increment){
            
             int targetIndex =beginIndex+increment;  //欲插入元素的下标
            
             while(targetIndex<array.length){
                    int temp =array[targetIndex];
                   
                    int previousIndex =targetIndex - increment;  //前一个元素下标,间隔为increment
                    while(previousIndex>=0&&array[previousIndex]>temp){
                           array[previousIndex+increment]= array[previousIndex];  //比欲插入数据项大的元素后移一位
                           previousIndex =previousIndex - increment;
                    }
                    array[previousIndex+increment]= temp;  //插入到合适的位置
                                        
                    targetIndex =targetIndex+increment;  //插入下一个元素
             }
            
      }

算法分析

希尔排序不像其他时间复杂度为O(N*log2N)的排序算法那么快,但是比选择排序和插入排序这种时间复杂度为O(N2)的排序算法还是要快得多,而且非常容易实现。它在最坏情况下的执行效率和在平均情况下的执行效率相比不会降低多少,而快速排序除非采取特殊措施,否则在最坏情况下的执行效率变得非常差。

迄今为止,还无法从理论上精准地分析希尔排序的效率,有各种各样基于试验的评估,估计它的时间级介于O(N3/2)与O(N7/6)之间。我们可以认为希尔排序的平均时间复杂度为O(N*(logN)2)。

作者:冰河winner
来源:CSDN
原文:https://blog.csdn.net/u012152619/article/details/47405799
版权声明:本文为博主原创文章,转载请附上博文链接!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

排序算法(六)——希尔排序 的相关文章

  • 04_Qt信号与槽机制

    文章目录 一 信号和槽 1 1 Qt5的书写方式 1 1 1 处理子窗口的信号不带参数 1 1 2 处理子窗口的信号带参数 使用函数指针 1 2 Qt4的书写方式 1 3 Lambda表达式 匿名函数对象 二 自定义信号槽 2 1 信号 2
  • Linux学习之权限

    在学习Linux权限之前 我们先理解一下关于Linux内核与shell外壳之间的关系 shell命令以及运行原理 Linux严格意义上说的是一个操作系统 我们称之为 核心 kernel 但我们一般用户 不能直接使用kernel 而是通过ke

随机推荐

  • 室友打了一把端游,我入门了Vue

    快速入门Vue 多种选择器 class选择器 标签选择器 data数据对象 Vue 指令 设置标签的文本值 textContent 设置标签的innerHtml v html 为元素绑定事件 v on 根据表达式的真假 切换元素的显示和隐藏
  • 【Python基础】matplotlib字体设置看这一篇就够了

    本文示例文件已上传至我的Github仓库https github com CNFeffery DataScienceStudyNotes 1 简介 matplotlib作为数据可视化的利器 被广泛用于数据分析之中 但不太友好的是matplo
  • 全数字锁相环(DPLL)的原理简介以及verilog设计代码

    随着数字电路技术的发展 数字锁相环在调制解调 频率合成 FM 立体声解码 彩色副载波同步 图象处理等各个方面得到了广泛的应用 数字锁相环不仅吸收了数字电路可靠性高 体积小 价格低等优点 还解决了模拟锁相环的直流零点漂移 器件饱和及易受电源和
  • 微信小程序——数据绑定

    在微信小程序中 可以通过以下代码实现数据绑定 在WXML中 使用双大括号 绑定数据 将数据渲染到对应的视图中
  • 【蓝桥杯】 (算法训练篇)K好数

    蓝桥杯 算法训练篇 K好数 问题描述 如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字 那么我们就说这个数是K好数 求L位K进制数中K好数的数目 例如K 4 L 2的时候 所有K好数为11 13 20 22 30 31 33
  • 一个人,仅30天!开发一款3D竞技足球游戏!他究竟经历了些什么?

    今天 晓衡向大家推荐一款Coco Store 优质 3D足球竞技游戏 资源 足球快斗 玩法介绍 游戏为 7V7 足球竞技类玩法 玩家控制本队的一个球员 脚下高亮圆圈显示的是玩家 其他球员和守门员为电脑AI控制 期间可以玩家可以换人 A按钮换
  • pycharm tips pycharm 使用技巧

    你好 这里只是pycharm tips 的翻译内容 任何工具窗口中的Esc键都将焦点移动到编辑器 Shift Esc将焦点移动到编辑器 并隐藏当前 或最后一个活动 工具窗口 F12键将焦点从编辑器移动到最后一个聚焦工具窗口 在编辑器中Ctr
  • Python语言程序设计 第一周习题

    Python语言程序设计 第一周习题 习题1 获得用户输入的一个整数 参考该整数值 打印输出 Hello World 要求 如果输入值是0 直接输出 Hello World 如果输入值大于0 以两个字符一行方式输出 Hello W
  • ESP32使用Arduino发布和订阅MQTT

    该项目展示了如何在ESP32上使用MQTT通信协议来发布消息和订阅主题 举例来说 我们会将BME280传感器的读数发布到Node RED仪表板 并控制ESP32输出 我们将使用Arduino IDE对ESP32进行编程 介绍 在此示例中 有
  • Ubuntu-16.06 + OpenCV-3.3.0 + 一些常见的问题

    前言 2017 11 18 根据实践过程整理出第一版 2018 01 05 更新对 pkgconfig 的说明 今天在跑一个faster rcnn的案例 https pjreddie com darknet yolo 涉及到编译 openC
  • tomcat 虚拟目录和目录浏览设置

    为了方便开发 需要开设置虚拟目录和目录浏览 如果是生产环境就不要开放目录浏览 设置虚拟目录 先建 d site 设置 CATALINA HOME bin conf server conf
  • Android--使用相对布局搭建用户注册界面

  • oracle:any,some,all的区别

    相关例子 SELECT emp empno emp ename emp job emp sal FROM scott emp WHERE sal gt any SELECT sal FROM scott emp WHERE job MANA
  • Spring 过滤器 拦截器 AOP区别

    简介 这几天在回顾Spring的AOP时 对过滤器 拦截器 AOP的关系有点好奇 故记录做以备份 在实现一些公共逻辑的时候 很多功能通过过滤器 拦截器 AOP都能实现 但是不同的方式有不同的效率 具体有什么区别 看下文描述 前后端交互基本逻
  • 使用Java VisualVM监控远程JVM(远程服务器为linux配置)

    我们经常需要对我们的开发的软件做各种测试 软件对系统资源的使用情况更是不可少 目前有多个监控工具 相比JProfiler对系统资源尤其是内存的消耗是非常庞大 JDK1 6开始自带的VisualVM就是不错的监控工具 这个工具就在JAVA H
  • C++ 函数重载(overroad) 覆盖(override) 隐藏(hide) 的区别

    原文转自 http blog chinaunix net u 15921 showart 227111 html 成员函数被重载的特征 1 相同的范围 在同一个类中 2 函数名字相同 3 参数不同 4 virtual 关键字可有可无 覆盖是
  • 点到UI 不会误点到物体

    这几天在做捕鱼达人游戏时发现 当鼠标点击UI时 炮台的子弹也会发射子弹 这样会影响用户体验 然后网上百度了一波 发现在UGUI系统上 EventSystem提供了一些方法 那就是EventSystem current IsPointerOv
  • ZeroMQ入门

    官网 ZeroMQ 简介 ZeroMQ是一个库 不是消息队列也不是消息中间件 介于应用层和传输层之间 按照TCP IP划分 传统的Socket通信模式需要创建连接 销毁连接 选择协议等一些列操作 而ZeroMQ是在Socket封装一层的并行
  • Java使用多线程查询数据

    目录 前言 实例 前言 什么是进程 进程 是操作系统的概念 一个独立运行的程序 就是一个 进程 什么是线程 线程 是由 进程创建 的 一个进程可以创建任意多的线程 每个线程都包含一些代码 线程中的代码会同主进程或者其他线程 同时运行 什么是
  • 排序算法(六)——希尔排序

    基本思想 希尔排序是基于插入排序的 又叫缩小增量排序 在插入排序中 标记符左边的元素是有序的 右边的是没有排过序的 这个算法取出标记符所指向的数据 存入一个临时变量 接着 在左边有序的数组中找到临时变量应该插入的位置 然后将插入位置之后的元