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

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

相关文章

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.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

C++快速排序超详细讲解

《C++快速排序超详细讲解》快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下... 目录一、快速排序原理二、快速排序标准代码三、代码解析四、使用while循环的快速排序1.代码代码1.由快

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri