八大排序算法--希尔排序(动图理解)

目录

希尔排序

概念

算法思路

动画演示

代码如下

复杂度分析

时间复杂度测试

运行结果

 完整代码

 创作不易,如果本篇博客对您有一定的帮助,大家记得留言+点赞哦。


希尔排序

概念

希尔排序是插入排序的一种,是对直接插入排序的优化。其特点在于分组排序。

算法思路

希尔排序是按照其设计者希尔的名字命名的,他对插入排序的效率进行了分析,得出如下结论:

        1.在最坏情况下即待排序序列为逆序时,需要消耗O(n^2)的时间
        2.在最好情况下即待排序序列为顺序时,需要消耗O(n)的时间


于是希尔就想:若是能先将待排序序列进行一次预排序,使待排序序列接近有序,然后再对该序列进行一次插入排序。因此此时直接插入排序的时间复杂度为O(n),那么只需控制预排序阶段的时间复杂度小于O(n^2)那么整体的时间复杂度就比插入排序的时间复杂度低了。

那具体的预排序应该怎么做才会时间复杂度满足要求呢?

        1.先选定一个小于n的整数gap(一般情况下是将n/2作为gap)作为第一增量,然后将所有距离为gap的元素分为一组,并对每一组进行插入排序
        2.重复步骤1,直到gap等于1停止,这时整个序列被分到了一组,进行一次直接插入排序,排序完成

你可能会疑惑,为什么gap由大到小?

因为gap越大,数据挪动的越快,耗时少;gap越小,数据挪动的越慢,耗时多。前期让gap较大,可以让数据快速移动到自己对应位置附近,减少挪动次数。

动画演示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Is6Arbg-1668608929993)(希尔排序.assets/动画.gif)]

 

我们来举一个实例:

 

首先gap取5,此时相隔距离为5的元素分到了一组(一共五组,每组两个元素),然后对每一组分别进行插入排序

 

gap折半为2,此时相隔距离为2的元素被分到了一组(一共两组,每组五个元素),然后对每一组分别进行插入排序

 

gap再次折半为1,此时所有元素被分到了一组,对它进行插入排序,至此插入排序完成

 

本例中前两趟就是希尔排序的预排序,最后一趟就是希尔排序的插入排序
 

代码如下

public static void shellSort(int[] a){int gal = a.length;while(gal>1) {int j = 0;gal/=2;   //特别之处gal  分组排序 5 3 1.。。//核心for (int i = gal; i < a.length; i++) {j = i-gal;if(a[j] > a[i]) {int tmp = a[j];a[j] = a[i];a[i] = tmp;}}}}

复杂度分析

希尔排序的时间复杂度并不好计算,因为 gap的取值方法很多中,导致很难去计算,下面是两位老师书中给出的解释。

 

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

     时间复杂度  n^1.3 -- n^1.5  说不准  与每次分组的个数gap有关
     空间复杂度 O(1)
     稳定性 不稳定 当有几个相同的数字时,排序后相对位置会改变

时间复杂度测试

接下来我们试着用大量数据测试一下。

int[] a = new int[10_0000];  //10万个数据测试

1.orderArray函数实现生成一个基本有序数列,即从小到大排列。

public static void orderArray(int[] a) {for (int i = 0; i < a.length; i++) {a[i] = i;}}


2.notOrderArray函数生成一个倒序数列,即从大到小排列。

public static void notOrderArray(int[] a) {for (int i = 0; i < a.length; i++) {a[i] = a.length-i;}}


3.randomArray函数生成一个随机无序数列。

 public static void randomArray(int[] a) {Random random = new Random();for (int i = 0; i < a.length; i++) {a[i] = random.nextInt(10_0000);}}


4.testInsertSort函数测试   System.currentTimeMillis() 返回值单位是毫秒

 

 public static void testInsertSort(int[] a){int[] tmpArray = Arrays.copyOf(a,a.length);long startTime = System.currentTimeMillis();    //注意用long接收shellSort(tmpArray);long endTime = System.currentTimeMillis();  //返回单位是毫秒System.out.println("直接插入排序耗时:"+(endTime-startTime));}


5.main函数调用执行

public static void main(String[] args) {int[] a = new int[10_0000];//有序System.out.println("基本有序数列");orderArray(a);testInsertSort(a);//倒序System.out.println("逆序数列");notOrderArray(a);testInsertSort(a);//随机乱序System.out.println("无序数列");randomArray(a);testInsertSort(a);}

运行结果

         

 希尔排序和直接插入排序都属于插入排序,而希尔排序更是直接插入排序的优化。对比上文直接插入排序的测试结果。

            

 可以看出,希尔排序确实快了许多。并且耗时稳定。

 完整代码

import java.util.Random;public class sort {public static void main(String[] args) {int[] a = new int[10_0000];//有序System.out.println("基本有序数列");orderArray(a);testInsertSort(a);//无序System.out.println("逆序数列");notOrderArray(a);testInsertSort(a);//乱序System.out.println("无序数列");randomArray(a);testInsertSort(a);}//希尔排序  是插入排序的优化//时间复杂度  n^1.3 -- n^1.5  说不准  与每次分组的个数有关//空间复杂度 O(1)//稳定性 不稳定 当有几个相同的数字时,排序后相对位置会改变public static void shellSort(int[] a){int gal = a.length;while(gal>1) {int j = 0;gal/=2;   //特别之处gal  分组排序 5 3 1.。。//核心for (int i = gal; i < a.length; i++) {j = i-gal;if(a[j] > a[i]) {int tmp = a[j];a[j] = a[i];a[i] = tmp;}}}}//生成有序数组  从小到大排列public static void orderArray(int[] a) {for (int i = 0; i < a.length; i++) {a[i] = i;}}//n无序 其实就是从大到小排列public static void notOrderArray(int[] a) {for (int i = 0; i < a.length; i++) {a[i] = a.length-i;}}//乱序 随机生成序列public static void randomArray(int[] a) {Random random = new Random();for (int i = 0; i < a.length; i++) {a[i] = random.nextInt(10_0000);}}//大量数据测试public static void testInsertSort(int[] a){int[] tmpArray = Arrays.copyOf(a,a.length);long startTime = System.currentTimeMillis();    //注意用long接收shellSort(tmpArray);long endTime = System.currentTimeMillis();System.out.println("希尔排序耗时:"+(endTime-startTime));}}

 创作不易,如果本篇博客对您有一定的帮助,大家记得留言+点赞哦。

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

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

相关文章

华为数通HCIP-IP组播基础

点到点业务&#xff1a;比如FTP&#xff0c;WEB业务&#xff0c;此类业务主要特点是不同的用户有不同的需求&#xff0c;比如用户A需要下载资料A&#xff0c;用户B需要下载资料B。此类业务一般由单播承载&#xff0c;服务器对于不同用户发送不同的点到点数据流。 ospf、isis…

TP DP PP 并行训练方法介绍

这里写目录标题 张量并行TP流水线并行 PPnaive模型并行GPipePipeDream 数据并行DPFSDP 张量并行TP 挖坑 流水线并行 PP 经典的流水线并行范式有Google推出的Gpipe&#xff0c;和微软推出的PipeDream。两者的推出时间都在2019年左右&#xff0c;大体设计框架一致。主要差别为…

【Apollo学习笔记】—— Cyber RT之调度

文章目录 前言相关代码整理 调度介绍Cyber RT的改进实时操作系统资源限制&优先级协程 Cyber RT调度策略任务窃取两种任务类型componen组件自定义任务 Cyber调度实践配置文件DAG文件cyber_launch文件component组件BUILD文件 问题参考 前言 本文是对Cyber RT的学习记录,文章可…

devops(前端)

1.前言 前端的打包流程和后端的流程是一样的&#xff0c;只是打包的环境和制作的镜像有所不同&#xff0c;前端需要使用nodejs环境打包&#xff0c;镜像也是使用nginx镜像&#xff0c;因为用的是k8s的pod运行镜像&#xff0c;还需要使用configmap挂载nginx的配置&#xff0c;一…

二、vagrant中安装centos-7

篇章二、vagrant中安装centos-7 前言 使用Vagrant创建镜像时&#xff0c;需要指定一个镜像&#xff0c;也就是box&#xff0c;若不存在Vagrant则会先从网上下载&#xff0c;而后缓存在本地目录下。 Vagrant有一个 镜像网站 &#xff0c;可以根据需要在这个网站中下载所需镜像…

11-矩阵(matrix)_方阵_对称阵_单位阵_对角阵

矩阵及其运算 [ a 11 ⋯ a 1 n ⋯ ⋯ ⋯ a m 1 ⋯ a m n ] \begin{bmatrix} a_{11} & \cdots & a_{1n} \\ \cdots & \cdots & \cdots \\ a_{m1} & \cdots & a_{mn} \\ \end{bmatrix} ​a11​⋯am1​​⋯⋯⋯​a1n​⋯amn​​ ​ 矩阵就是二维数组&…

JavaWeb(7)——前端综合案例1(面向对象)

目录 一、实例需求 ❗ 二、 实现 &#x1f3af; 三、代码优化 &#x1f482; &#x1f4bb; &#x1f474;&#x1f3fd; 四、继续优化和总结 &#x1f315;&#x1f44d; 五、需要注意的 ❌ 一、实例需求 ❗ JS进阶-day3-184-综合案例-模态框构造函数写法 二、 实现 &a…

Error message “error:0308010C:digital envelope routines::unsupported“

https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported nvm install 16即可解决

花费7元训练自己的GPT 2模型

在上一篇博客中&#xff0c;我介绍了用Tensorflow来重现GPT 1的模型和训练的过程。这次我打算用Pytorch来重现GPT 2的模型并从头进行训练。 GPT 2的模型相比GPT 1的改进并不多&#xff0c;主要在以下方面&#xff1a; 1. GPT 2把layer normalization放在每个decoder block的前…

MySQL索引特性

MySQL索引特性 理论部分&#xff1a;一.什么是索引&#xff1f;二.索引的概念三.认识磁盘1. 磁盘的结构2. 磁盘的随机访问&#xff08;Random Access&#xff09;与连续访问&#xff08;Sequential Access&#xff09; 四.MySQL与磁盘交互的基本单位五.索引的理解1. 主键索引现…

SpringBoot 实现数据加密脱敏(注解 + 反射 + AOP)

SpringBoot 实现数据加密脱敏&#xff08;注解 反射 AOP&#xff09; 场景&#xff1a;响应政府要求&#xff0c;商业软件应保证用户基本信息不被泄露&#xff0c;不能直接展示用户手机号&#xff0c;身份证&#xff0c;地址等敏感信息。 根据上面场景描述&#xff0c;我们…

不同 vlan 之间互通

不同VLAN间的用户要实现互通 如果是不同网段用户&#xff0c;常用的技术为&#xff1a;vlanif 和 单臂路由都可以解决不同 vlan 之间三层包互通问题。 VLANIF VLANIF接口是一种三层的逻辑接口&#xff0c;能实现不同VLAN间&#xff0c;不同网段的用户进行三层互通。由于配置…

概率论与数理统计复习总结3

概率论与数理统计复习总结&#xff0c;仅供笔者复习使用&#xff0c;参考教材&#xff1a; 《概率论与数理统计》/ 荣腾中主编. — 第 2 版. 高等教育出版社《2024高途考研数学——概率基础精讲》王喆 概率论与数理统计实际上是两个互补的分支&#xff1a;概率论 在 已知随机…

【使用维纳滤波进行信号分离】基于维纳-霍普夫方程的信号分离或去噪维纳滤波器估计(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

error: #5: cannot open source input file “core_cmInstr.h“

GD32F103VET6和STM32F103VET6引脚兼容。 GD32F103VET6工程模板需要包含头文件&#xff1a;core_cmInstr.h和core_cmFunc.h&#xff0c;这个和STM32F103还是有区别的&#xff0c;否则会报错&#xff0c;如下&#xff1a; error: #5: cannot open source input file "core…

两个镜头、视野、分辨率不同的相机(rgb、红外)的视野校正

文章目录 背景实际效果查找资料资料1资料2 解决方案最终结果 背景 目前在做的项目用到两个摄像头&#xff0c;一个是热成像摄像头、另一个是普通的rgb摄像头。 一开始的目标是让他们像素级重合&#xff0c;使得点击rgb图像时&#xff0c;即可知道其像素对应的温度。但是在尝试…

js中的设计模式

设计模式 代码整体的结构会更加清楚&#xff0c;管理起来会更加方便&#xff0c;更好地维护 设计模式是一种思想 发布订阅 模块化开发 导入很多模块 容器即数组存储未来要执行的方法&#xff0c;同addEventListener 数组塌陷问题* 由于删除了元素&#xff0c;导致从删除元素的位…

ppt怎么压缩到10m以内?分享好用的压缩方法

PPT是一种常见的演示文稿格式&#xff0c;有时候文件过大&#xff0c;我们会遇到无法发送、上传的现象&#xff0c;这时候简单的解决方法就是压缩其大小&#xff0c;那怎么才能将PPT压缩到10M以内呢&#xff1f; PPT文件大小受到影响的主要因素就是以下几点&#xff1a; 1、图…

VR全景旅游,智慧文旅发展新趋势!

引言&#xff1a; VR全景旅游正在带领我们踏上一场全新的旅行体验。这种沉浸式的旅行方式&#xff0c;让我们可以足不出户&#xff0c;却又身临其境地感受世界各地的美景。 一&#xff0e;VR全景旅游是什么&#xff1f; VR全景旅游是一种借助虚拟现实技术&#xff0c;让用户…

AssetBundle学习

官方文档&#xff1a;AssetBundle 工作流程 - Unity 手册 (unity3d.com) 之前写的博客&#xff1a;AssetBundle学习_zaizai1007的博客-CSDN博客 使用流程图&#xff1a; 1&#xff0c;指定资源的AssetBundle属性 &#xff08;xxxa/xxx&#xff09;这里xxxa会生成目录&…