【数据结构】排序算法---希尔排序(动图演示)

embedded/2025/3/19 9:26:15/

在这里插入图片描述

文章目录

  • 1. 定义
  • 2. 算法步骤
  • 3. 动图演示
  • 4. 性质
  • 5. 算法分析
  • 6. 代码实现
    • C语言
    • Python
    • Java
    • C++
    • Go
  • 结语

1. 定义

希尔排序(英语:Shell sort),也称为缩小增量排序法,是[直接插入排序]的一种改进版本。希尔排序以它的发明者希尔(英语:Donald Shell)命名。是第一个突破 O ( n 2 ) O(n^2) O(n2)算法>排序算法,它与插入排序的不同之处在于,它会优先比较距离较远的元素。

2. 算法步骤

排序对不相邻的记录进行比较和移动:

  1. 将待排序序列分为若干子序列(每个子序列的元素在原始数组中间距相同);
  2. 对这些子序列进行插入排序;
  3. 减小每个子序列中元素之间的间距,重复上述过程直至间距减少为1。

3. 动图演示

在这里插入图片描述

基本思想:先选定一个整数(通常是 g a p = n / 3 + 1 gap = n/3+1 gap=n/3+1),把待排序文件所有记录分成各组,所有的距离相等的记录分在同一组内,并对每一组内的记录进行排序,然后 g a p = g a p / 3 + 1 gap=gap/3+1 gap=gap/3+1得到下一个整数,再将数组分成各组,进行插入排序,当 g a p = 1 gap=1 gap=1时,就相当于直接插入排序

它是在直接插入算法>排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接入算法>排序算法的。

在这里插入图片描述

g a p > 1 gap > 1 gap>1时都是预排序,目的是让数组更接近于有序。当 g a p = = 1 gap == 1 gap==1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。

4. 性质

稳定性

希尔排序是一种不稳定的算法>排序算法

空间复杂度

希尔排序的空间复杂度为 O ( 1 ) O(1) O(1)

时间复杂度

希尔排序的最优时间复杂度为 O ( n ) O(n) O(n)

希尔排序的平均时间复杂度和最坏时间复杂度与间距序列的选取有关。设间距序列为 H H H,有 H H H的两种经典选取方式,这两种选取方式均使得算法>排序算法的复杂度降为级别 O ( n 2 ) O(n^2) O(n2)

希尔排序的平均时间复杂度可以降为 O ( n 1.3 ) O(n^{1.3}) O(n1.3)

下面是希尔排序时间复杂度的估算:

外层循环:

外层循环的时间复杂度可以直接给出为: O ( l o g 2 n ) O(log_2n) O(log2n)或者 O ( l o g 3 n ) O(log_3 n) O(log3n),即 O ( l o g n ) O(logn) O(logn)

内层循环:

在这里插入图片描述

假设一共有n个数据,合计gap组,则每组为n/gap个;在每组中,插入移动的次数最坏的情况下为

1 + 2 + 3 + . . . . + ( n g a p − 1 ) 1 + 2 + 3 + .... + ({n\over gap} - 1) 1+2+3+....+(gapn1) ,一共是gap组,因此:

总计最坏情况下移动总数为: g a p ∗ [ 1 + 2 + 3 + . . . . + ( n g a p − 1 ) ] gap∗[1 + 2 + 3 + .... + ({n \over gap} - 1)] gap[1+2+3+....+(gapn1)]

gap取值有(以除3为例):n/3 n/9 n/27 … 2 1

  • 当gap为n/3时,移动总数为: n 3 ∗ ( 1 + 2 ) = n {n \over 3}*(1+2)=n 3n(1+2)=n

  • 当gap为n/9时,移动总数为: n 9 ∗ ( 1 + 2 + 3 + . . . . + 8 ) = n 9 ∗ 8 ( 1 + 8 ) 2 = 4 n {n \over 9}*(1+2+3+....+8)={n \over 9}*{8(1+8) \over 2}=4n 9n(1+2+3+....+8)=9n28(1+8)=4n

  • 最后一躺,gap=1即直接插入排序,内层循环排序消耗为n

通过以上的分析,可以画出这样的图:

在这里插入图片描述

因此,希尔排序在最初和最后的排序的次数都为n,即前一阶段排序次数是逐渐上升的状态,当到达某一顶点时,排序次数逐渐下降至n,而该顶点的计算暂时无法给出具体的计算过程

希尔排序时间复杂度不好计算,因为gap的取值很多,导致很难去计算,因此很多书中给出的希尔排序的时间复杂度都不固定。《数据结构(C语言版)》— 严蔚敏书中给出的时间复杂度为:

在这里插入图片描述

5. 算法分析

希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第4版)》的合著者Robert Sedgewick提出的。

6. 代码实现

C语言

void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){//推荐写法:除3gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++){int end = i;int tmp = a[end + gap];while (end >= 0){if (a[end] > tmp){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}

Python

def shellSort(arr):import mathgap=1while(gap < len(arr)/3):gap = gap*3+1while gap > 0:for i in range(gap,len(arr)):temp = arr[i]j = i-gapwhile j >=0 and arr[j] > temp:arr[j+gap]=arr[j]j-=gaparr[j+gap] = tempgap = math.floor(gap/3)return arr

Java

public static void shellSort(int[] arr) {int length = arr.length;int temp;for (int step = length / 2; step >= 1; step /= 2) {for (int i = step; i < length; i++) {temp = arr[i];int j = i - step;while (j >= 0 && arr[j] > temp) {arr[j + step] = arr[j];j -= step;}arr[j + step] = temp;}}
}

C++

template<typename T>
void shell_sort(T array[], int length) {int h = 1;while (h < length / 3) {h = 3 * h + 1;}while (h >= 1) {for (int i = h; i < length; i++) {for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {std::swap(array[j], array[j - h]);}}h = h / 3;}
}

Go

func shellSort(arr []int) []int {length := len(arr)gap := 1for gap < length/3 {gap = gap*3 + 1}for gap > 0 {for i := gap; i < length; i++ {temp := arr[i]j := i - gapfor j >= 0 && arr[j] > temp {arr[j+gap] = arr[j]j -= gap}arr[j+gap] = temp}gap = gap / 3}return arr
}

结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下。

也可以点点关注,避免以后找不到我哦!

Crossoads主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力!

带你初步了解算法>排序算法:https://blog.csdn.net/2301_80191662/article/details/142211265
直接插入排序:https://blog.csdn.net/2301_80191662/article/details/142300973
希尔排序:https://blog.csdn.net/2301_80191662/article/details/142302553
直接选择排序:https://blog.csdn.net/2301_80191662/article/details/142312028
堆排序:https://blog.csdn.net/2301_80191662/article/details/142312338
冒泡排序:https://blog.csdn.net/2301_80191662/article/details/142324131
快速排序:https://blog.csdn.net/2301_80191662/article/details/142324307
归并排序:https://blog.csdn.net/2301_80191662/article/details/142350640
计数排序:https://blog.csdn.net/2301_80191662/article/details/142350741
桶排序:https://blog.csdn.net/2301_80191662/article/details/142375338
基数排序:https://blog.csdn.net/2301_80191662/article/details/142375592
十大经典算法>排序算法总结与分析:https://blog.csdn.net/2301_80191662/article/details/142211564

在这里插入图片描述


http://www.ppmy.cn/embedded/173818.html

相关文章

【JAVA】】深入浅出了解cookie、session、jwt

文章目录 前言一、首先了解http的cookie是什么&#xff1f;Cookie 属性及其含义1. NameValue2. Expires3. Max-Age4. Domain5. Path6. Secure7. HttpOnly8. SameSite示例 Cookie 分类1. Session Cookies2. Persistent Cookies3. First-Party Cookies4. Third-Party Cookies 二、…

火山云对比阿里云的优势在哪里

首先&#xff0c;我得回忆一下火山云和阿里云各自的特点&#xff0c;然后进行比较。火山云是字节跳动旗下的云服务&#xff0c;可能在某些方面有字节的特色&#xff0c;比如视频处理、大数据或者AI相关的服务。而阿里云作为国内最大的云服务提供商&#xff0c;功能全面&#xf…

嵌入式硬件篇---龙芯UART通信

文章目录 前言一、代码结构解析1. 头文件部分作用 2. 宏定义与全局变量龙芯特性 3. 主函数流程关键点 4. UART发送函数龙芯实现 5. 串口配置函数&#xff08;set_port&#xff09;龙芯注意事项 6. GPIO控制函数龙芯GPIO特性 7. PWM控制函数龙芯PWM实现 二、龙芯UART深度解析1. …

Qt QML解决SVG图片显示模糊的问题

前言 在QML中直接使用SVG图片&#xff0c;使用Image控件加载资源&#xff0c;显示出来图片是模糊的&#xff0c;很影响使用体验。本文介绍重新绘制SVG图片&#xff0c;然后注册到QML中使用。 效果图&#xff1a; 左边是直接使用Image加载资源显示的效果 右边是重绘后的效果 …

Java集合的底层原理

目录 Collection Arraylist HashSet 介绍 哈希值 哈希表的基本概念 HashSet 的内部实现 HashMap 哈希碰撞的处理 总结 TreeSet 特点 红黑树的特性 红黑规则 TreeSet 的内部实现 1. 存储结构 2. 添加元素&#xff08;重点&#xff09; 3. 查找元素 4. 删除元…

DexClassLoader 动态加载机制

DexClassLoader 动态加载机制 DexClassLoader 是 Android 提供的 动态加载 DEX&#xff08;Dalvik Executable&#xff09;文件 的工具&#xff0c;允许应用在 运行时 加载 .dex 或 .apk 文件中的类&#xff0c;而不需要在编译时静态引入。 1. DexClassLoader 介绍 DexClassL…

使用PyMongo操作MongoDB(一)

使用PyMongo操作MongoDB MongoDB作为一款流行的NoSQL数据库&#xff0c;以其灵活的数据模型和强大的查询能力受到开发者青睐。通过PyMongo库&#xff0c;我们可以在Python中轻松实现与MongoDB的交互。本文将系统介绍PyMongo的安装、连接及数据库操作全流程。 一、环境准备 安…

Redis客户端Jedis、Lettuce 和 Redisson优缺点总结

https://developer.huawei.com/consumer/cn/blog/topic/03825550899620047 Redis 官方推荐的 Java 客户端有Jedis、Lettuce 和 Redisson。本文总结这些客服端的优缺点 1. Jedis Jedis 是老牌的 Redis 的 Java 实现客户端&#xff0c;提供了比较全面的 Redis 命令的支持&#…