数据结构与算法之希尔排序

前言

希尔排序(Shell Sort)是插入排序的一种高效改进版本,由 Donald Shell 于 1959 年提出。它的核心思想是通过分组插入排序来减少数据交换的次数,从而提升排序效率。

一、 核心思想:缩小增量排序

希尔排序引入了"增量(Gap)"的概念。它不像直接插入排序那样逐个比较相邻元素,而是将整个待排序的序列分割成若干个子序列,对每个子序列进行插入排序。随着增量逐渐减小,整个序列会变得越来越"基本有序",当增量减至 1 时,整个序列实际上就是一次直接插入排序,但此时数据已经基本有序,所以移动次数会大大减少。

二、 算法步骤

假设我们有数组:[8, 3, 1, 9, 5, 7, 2, 4, 6]为例,看一下算法排序的过程

1.选择增量序列

首先我们选择一个增量序列 gap,通常初始值取数组长度的一半(n/2)。

这里的n/2向下取整。

将元素按间隔4分组:

组1: 8, 5, 6 → 排序后: 5, 6, 8

组2: 3, 7 → 排序后: 3, 7

组3: 1, 2 → 排序后: 1, 2

组4: 9, 4 → 排序后: 4, 9

数组变为:5, 3, 1, 4, 6, 7, 2, 9, 8

2.分组排序

将数组按增量 gap分成若干组,对每组进行插入排序。

这里的间隔为2.

组1: 5, 1, 6, 2, 8 → 排序后: 1, 2, 5, 6, 8

组2: 3, 4, 7, 9 → 排序后: 3, 4, 7, 9

数组变为:1, 3, 2, 4, 5, 7, 6, 9, 8

3.缩小增量

将增量 gap缩小(通常为 gap/2或 gap/3),重复步骤 2。

这里的gap = 1。直接执行下一个步骤。

4.最终排序

当增量 gap缩小为 1 时,对整个数组进行一次直接插入排序,排序完成。

最终排序:1, 2, 3, 4, 5, 6, 7, 8, 9

三、 代码实现(C语言)

复制代码
#include <stdio.h>

void shellSort(int arr[], int n) {
    // 初始增量 gap 为数组长度的一半
    for (int gap = n / 2; gap > 0; gap /= 2) {
        // 从第 gap 个元素开始,逐个对其所在组进行直接插入排序
        for (int i = gap; i < n; i++) {
            int temp = arr[i]; // 待插入的元素
            int j;
            // 对组内元素进行插入排序
            for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
                arr[j] = arr[j - gap]; // 移动元素
            }
            arr[j] = temp; // 插入元素
        }
    }
}

int main() {
    int arr[] = {9, 6, 7, 3, 1, 5, 4, 8, 2};
    int n = sizeof(arr) / sizeof(arr[0]);
    
    shellSort(arr, n);
    
    printf("排序结果: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

四、 性能分析

特性 描述
时间复杂度​ 取决于增量序列的选择。最坏情况为 O(n²),使用 Hibbard 增量序列可优化至 O(n^(3/2))。
空间复杂度​ O(1),是原地排序算法。
稳定性​ 不稳定。由于分组排序,相等的元素可能会被分到不同的组,导致相对顺序改变。

五、 总结

希尔排序是插入排序的优化版 ,它通过"先宏观调整,后微观调整 "的策略,有效减少了数据交换的次数。虽然它不如快速排序或归并排序那样高效,但它在中等规模数据的排序中表现良好,且代码实现相对简单,是理解排序算法优化思路的重要案例。

相关推荐
Code_Solitude7 小时前
C语言动态内存 + 柔性数组 + 数组名退化
c语言·算法·柔性数组
上海潭龙东海科技有限公司7 小时前
客运站管控之动态孪生技术方案(新增一屏管控模块
数据仓库·人工智能·算法·重构·动态规划
YLCHUP9 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
思麟呀10 小时前
背包DP(01背包+完全背包)
c++·算法
笑容掩饰我的失落11 小时前
区块链从小白到精通(七):Solidity 语法精讲——数据类型、函数、修饰器与事件
算法·区块链·php·智能合约·哈希算法
Pniubi12 小时前
力扣24. 两两交换链表中的节点(递归)
算法·leetcode·链表
nice_lcj52012 小时前
LRU 缓存入门:它是什么、怎么用、面试怎么手写
java·数据结构·缓存·面试·lru
꧁细听勿语情꧂13 小时前
直接选择排序,堆排序,冒泡排序,递归快速排序、hoare版本、挖坑法、lomuto前后指针,非递归快速排序
c语言·开发语言·数据结构·算法
俊俊几年的13 小时前
动态规划(Dynamic Programming)详解:从入门到 LeetCode Hot 100
linux·c++·算法·leetcode·嵌入式·动态规划·c