嵌入式 - 数据结构与算法:(1-13)排序算法 - 希尔排序(Shell Sort)

上一篇 下一篇
快速排序

目 录


4)希尔排序(Shell Sort)

希尔排序,又称 "缩小增量排序",是插入排序的一种高效改进版本,由 Donald Shell 于 1959 年提出

参考视频:数据结构合集 - 希尔排序(算法过程, 效率, 稳定性分析)_哔哩哔哩_bilibili

4.1)核心思想

插入排序简介:(将数组分为"已排序"和"未排序"两部分)初始时,第一个元素视为已排序。然后依次从"未排序"部分取出元素,插入到"已排序"部分的正确位置(当比左边的大,比右边的小,则就到了正确的位置),直到所有元素都被处理。

希尔排序核心思想: 先让数组"大致有序",再进行一次精细的插入排序。

它通过引入一个 间隔(gap) ,将原始数组划分为若干个子序列,对每个子序列分别进行插入排序。随着 gap 逐步缩小(通常每次除以 2),子序列越来越长,数组也越来越接近有序。当 gap = 1 时,就退化为一次标准的插入排序------但此时数据已基本有序,效率极高。

4.2)算法步骤(升序)

  1. 选择一个初始 间隔 gap (通常取 n / 2,n 为数组长度,向下取整);
  2. 将数组按 gap 分成若干组(例如 gap=3,则索引 0,3,6... 为一组;1,4,7... 为一组等);
  3. 对每组内部进行 插入排序;
  4. 缩小 gap(如 gap = gap / 2);
  5. 重复步骤 2~4,直到 gap = 1;
  6. 最后执行一次 gap = 1 的插入排序,完成整体排序。

关键优势:提前将大数"快速"移到后面,小数"快速"移到前面,避免插入排序在逆序时大量移动。

4.3)时间与空间复杂度

情况 时间复杂度(依赖 gap 序列)
最好 O(n log n)
平均 O(n^1.3) ~ O(n^(3/2))(常用 gap=n/2 时)
最坏 O(n²)(某些 gap 序列下)
  • 空间复杂度:O(1)(原地排序)
  • 稳定性:❌ 不稳定(跨组交换可能改变相等元素顺序)

注意:希尔排序的时间复杂度 依赖于 gap 序列的选择 ,常见 gap 序列:

  • Shell 原始:n/2, n/4, ..., 1
  • Knuth:1, 4, 13, 40, ...(公式:gap = gap * 3 + 1)
  • Sedgewick 等更优序列(工程中较少用)

4.4)C 语言代码示例

(使用 Shell 原始 gap 序列)

c 复制代码
#include <stdio.h>

/* 希尔排序函数(升序)*/
void shell_sort(int arr[], int n) {
    // 初始 gap 为数组长度的一半
    for (int gap = n / 2; gap > 0; gap /= 2) {
        // 对每个子序列进行插入排序
        for (int i = gap; i < n; i++) {
            int temp = arr[i];      // 当前要插入的元素
            int j = i;

            // 在子序列中向前比较并移动元素
            while (j >= gap && arr[j - gap] > temp) {
                arr[j] = arr[j - gap];
                j -= gap;
            }
            arr[j] = temp; // 插入到正确位置
        }
    }
}

// 打印数组
void print_array(int arr[], int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

/* 主函数:测试希尔排序 */
int main() {
    int arr[] = {64, 34, 25, 12, 22, 11, 90};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("原始数组: ");
    print_array(arr, n);

    shell_sort(arr, n);

    printf("排序后数组: ");
    print_array(arr, n);

    return 0;
}

运行结果如下:

复制代码
原始数组: 64 34 25 12 22 11 90 
排序后数组: 11 12 22 25 34 64 90 

执行过程示例(简略):

  • gap = 3 → 分组:
    [64, 12, 90], [34, 22], [25, 11] → 各组插入排序后 → [12, 22, 11, 64, 34, 25, 90]
  • gap = 1 → 整个数组插入排序 → 最终有序

相关推荐
倒头就睡的小比特4 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼4 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光4 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark4 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her14 天前
并查集-听课笔记
笔记·算法·并查集
码流子4 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven4 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark4 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218614 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法