【白话排序算法】希尔/谢尔排序法

2024-01-27 09:20

本文主要是介绍【白话排序算法】希尔/谢尔排序法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

谢尔排序法(Shell’s Sort)又称缩小增量排序法。他在1959年由谢尔(D.L.Shell)提出的。当时主流的排序算法时间复杂度都是 O ( n 2 ) O(n^2) O(n2)。谢尔排序是有望突破这个复杂度的一批算法之一。题外话,对比现在如此多O(nlogn)时间复杂度的排序算法,可见当时人们对排序算法的认知匮乏。你如果能穿越回60年前,绝对是一个了不起的人…

谢尔排序理解起来还是有些困难的。不过我可以试图解释下面这样一个思想,你应该能感觉到谢尔排序是可以降低时间复杂度的。

以下内容需要您对冒泡排序有一定的理解,可以看看我之前写的关于冒泡排序的文章。

在冒泡排序中,核心是相邻两个元素交替位置,在这个过程中,其实大量的没有必要的交换,即交换之后会再被交换。
在这里插入图片描述
观察一下9这个数,为了让他能够到正确的位置,所有其他元素都不得不进行位置的交替。而这些其他元素的位置交替仅仅是为了让9能够冒泡上去。

那么有没有可能在交替的过程中,让其他元素哪怕至少能够离其最终的位置近一些。因为我们知道,冒泡排序有一个特点:

若待排序的序列是倒序的,那么冒泡排序时间复杂度是 O ( n 2 ) O(n^2) O(n2),若待排序的序列本身就是有序的,时间复杂度仅仅为O(n)。即,若待排序的序列基本有序,时间复杂度将会大幅降低

谢尔排序正是利用了这样一个特点,当位置交替的时候,尽可能让交替变的有意义,即那些大的元素尽量往后排,而小的元素尽量往前排,让一趟交替后,让序列尽可能的有序一些,来达到最终降低时间复杂度的目的。

这样一个思想是可行的,你能明白么?下面来说一下如何实现。

为了能够让大的元素往后排,小的元素往前排,谢尔排序会以子序列的方式跳跃的交替元素的位置,这里也就是冒泡排序,进而让序列尽可能有序。
在这里插入图片描述
观察下上图,可以把相当颜色的元素集合看成一个子序列,并对子序列进行冒泡排序(或其他的排序方式),而一趟结束的结果是不是已经实现了某种程序上接近有序了?谢尔排序之后通过不断缩小间隔元素的大小,当间隔为1去进行排序的时候,已经相当于完整的冒泡排序,但此时序列已经基本有序。从而实现了尽可能的降低时间复杂度的目的,很巧妙吧。下面我来用JavaScript语言来实现下:

function ShellSort(seq) {let i, j, flag, temp, gap = seq.length;while(gap > 1) {gap = Math.floor(gap / 2);do {flag = 0;for (i=0;i<=seq.length-gap;i++) {j = i + gap;if (seq[i] > seq[j]) {temp = seq[i];seq[i] = seq[j];seq[j] = temp;flag = 1;}}} while (flag != 0)}
}
ShellSort(seq)
console.log(seq) // [1, 2, 3, 4, 5, 6, 6, 7, 9 ]

关于算法中的gap取值,实际上并没有确定的规则,每次取序列长度的一半似乎是一种比较常用的方法。

谢尔排序需要去仔细的思考其思想。相对于插入,选择,冒泡,包含后边说的快排,都难理解一些。希望读者能静下心来,慢慢想想,就不难理解了。

我来总结一下我个人的思考:谢尔排序就是通过排序子序列的方式,让原有的序列不断的接近有序,再利用基本有序的序列排序时间复杂度低的特性,来最终通过一次完整的排序保证结果有序。

另外值得注意的是,谢尔排序的时间复杂度是介于 O ( n 2 ) O(n^2) O(n2)与O(nlogn)的。

谢尔排序的由于也涉及到了跨元素间的交换,所以是一种不稳定的排序方式。

这篇关于【白话排序算法】希尔/谢尔排序法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/649793

相关文章

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

一文详解Java Stream的sorted自定义排序

《一文详解JavaStream的sorted自定义排序》Javastream中的sorted方法是用于对流中的元素进行排序的方法,它可以接受一个comparator参数,用于指定排序规则,sorte... 目录一、sorted 操作的基础原理二、自定义排序的实现方式1. Comparator 接口的 Lam

Java List排序实例代码详解

《JavaList排序实例代码详解》:本文主要介绍JavaList排序的相关资料,Java排序方法包括自然排序、自定义排序、Lambda简化及多条件排序,实现灵活且代码简洁,文中通过代码介绍的... 目录一、自然排序二、自定义排序规则三、使用 Lambda 表达式简化 Comparator四、多条件排序五、

JAVA数组中五种常见排序方法整理汇总

《JAVA数组中五种常见排序方法整理汇总》本文给大家分享五种常用的Java数组排序方法整理,每种方法结合示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录前言:法一:Arrays.sort()法二:冒泡排序法三:选择排序法四:反转排序法五:直接插入排序前言:几种常用的Java数组排序

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

Mybatis 传参与排序模糊查询功能实现

《Mybatis传参与排序模糊查询功能实现》:本文主要介绍Mybatis传参与排序模糊查询功能实现,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、#{ }和${ }传参的区别二、排序三、like查询四、数据库连接池五、mysql 开发企业规范一、#{ }和${ }传参的

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.