排序---希尔排序(Shell Sort)

一、希尔排序的起源与定义

希尔排序是1959年由美国计算机科学家唐纳德·希尔(Donald Shell)提出的排序算法,其本质是对插入排序的优化与改进,因此也被称为"缩小增量排序"(Diminishing Increment Sort)。

插入排序在处理近乎有序的数组时效率很高(时间复杂度接近O(n)),但在面对无序数组时,每次元素可能需要移动大量位置(最坏情况O(n²))。希尔排序通过引入"增量"概念,将数组分割为多个子序列并分别排序,逐步缩小增量直至为1,最终通过一次完整的插入排序完成整个数组的排序,从而大幅提升效率。

二、核心思想

希尔排序的核心思想可概括为"分组插入排序+逐步缩小增量":

  1. 分组:选择一个增量(gap),将数组按下标间隔为gap的规则分为若干子序列(例如,gap=3时,下标0、3、6...为一组,1、4、7...为另一组)。
  2. 子序列排序:对每个子序列执行插入排序,使每组内的元素相对有序。
  3. 缩小增量:减小gap的值(如gap=gap/2),重复分组和排序步骤。
  4. 最终排序:当gap=1时,整个数组被视为一个子序列,执行最后一次插入排序,此时数组已接近有序,插入排序效率极高。

通过这一过程,元素可以"跳跃式"地向最终位置移动,减少了插入排序中频繁的相邻元素交换,从而优化性能。

三、增量序列的选择

增量序列(gap序列)的选择是希尔排序性能的关键,直接影响算法效率。常见的增量序列有:

  1. 希尔原始增量gap = n/2, n/4, ..., 1(n为数组长度)。

    优点是简单易实现;缺点是最坏时间复杂度仍为O(n²),且增量间可能存在公因子(如4和2),导致分组重复。

  2. Knuth增量gap = (3^k - 1)/2(从小于n的最大增量开始,逐步减小)。

    例如,n=100时,增量序列为40、13、4、1。该序列避免了公因子问题,最坏时间复杂度优化至O(n^(3/2))。

  3. Hibbard增量gap = 2^k - 1(如1、3、7、15...)。

    最坏时间复杂度为O(n^(3/2)),实践中性能优于希尔原始增量。

  4. Sedgewick增量gap = 9*4^k - 9*2^k + 14^k - 3*2^k + 1(如1、5、19、41...)。

    目前已知性能较优的增量序列,最坏时间复杂度接近O(n^1.3)。

实际应用中,Knuth增量因实现简单且性能稳定,是常用选择。

四、工作原理示例

以数组 [12, 34, 54, 2, 3, 9, 8, 76, 52, 1](n=10)为例,使用Knuth增量序列(初始gap=4,因(3³-1)/2=13>10,故取(3²-1)/2=4),演示希尔排序过程:

  1. 第一轮:gap=4

    按间隔4分组,得到4个子序列:

    • 组1:[12, 9, 1]
    • 组2:[34, 8]
    • 组3:[54, 76]
    • 组4:[2, 52]

    对每组执行插入排序后,子序列变为:

    • 组1:[1, 9, 12]
    • 组2:[8, 34]
    • 组3:[54, 76]
    • 组4:[2, 52]

    合并后数组:[1, 8, 54, 2, 3, 9, 76, 52, 12, 34]

  2. 第二轮:gap=1 (Knuth增量下一个为(3¹-1)/2=1)

    此时gap=1,整个数组为一个子序列:[1, 8, 54, 2, 3, 9, 76, 52, 12, 34]

    执行插入排序,最终得到有序数组:[1, 2, 3, 8, 9, 12, 34, 52, 54, 76]

五、时间复杂度与空间复杂度
  • 时间复杂度

    希尔排序的时间复杂度依赖于增量序列,目前尚未有精确的数学证明。在常见增量序列中:

    • 希尔原始增量:最坏O(n²),平均O(n^1.5);
    • Knuth增量:最坏O(n^(3/2));
    • Sedgewick增量:最坏接近O(n^1.3)。
  • 空间复杂度

    仅需一个临时变量用于元素交换,因此空间复杂度为O(1)(原地排序)。

六、优缺点分析
  • 优点

    1. 效率高于简单插入排序,尤其对中等规模数组(n=1000~10000)表现优异;
    2. 原地排序,空间复杂度低;
    3. 实现简单,易于理解和编码。
  • 缺点

    1. 增量序列选择影响性能,需根据场景调整;
    2. 不稳定排序(相同元素可能因分组排序改变相对位置);
    3. 对大规模数据(n>10^5)效率不如快速排序、归并排序等高级算法。
七、C++实现示例

以下代码使用Knuth增量序列实现希尔排序,并包含测试用例:

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

// 希尔排序函数(使用希尔原始增量序列)
void shellSort(vector<int>& arr) {
    int n = arr.size();
    
    // 希尔原始增量:初始为n/2,每次减半直至为1
    for (int gap = n / 2; gap > 0; gap /= 2) {
        // 对每个子序列执行插入排序
        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;  // 插入待排序元素
        }
    }
}

// 打印数组
void printArray(const vector<int>& arr) {
    for (int num : arr) {
        cout << num << " ";
    }
    cout << endl;
}

// 测试
int main() {
    vector<int> arr = {12, 34, 54, 2, 3, 9, 8, 76, 52, 1};
    cout << "排序前:";
    printArray(arr);

    shellSort(arr);

    cout << "排序后:";
    printArray(arr);
    return 0;
}
    
八、代码解析
  1. 增量计算

    先通过 gap = gap * 3 + 1 计算小于数组长度的最大Knuth增量(如n=10时,gap初始为4)。

  2. 分组排序

    外层循环控制增量 gap 从大到小变化(gap = (gap-1)/3);中层循环遍历数组元素,从 gap 开始(跳过前gap个元素,它们是各子序列的第一个元素);内层循环对每个子序列执行插入排序------将 arr[i] 与同组前序元素(arr[j-gap])比较,若前序元素更大则后移,最终将 arr[i] 插入正确位置。

  3. 测试结果

    输入数组 [12, 34, 54, 2, 3, 9, 8, 76, 52, 1] 经排序后输出 [1, 2, 3, 8, 9, 12, 34, 52, 54, 76],符合预期。

九、应用场景

希尔排序适用于以下场景:

  • 中等规模数据(n=1000~10000)的排序;
  • 对空间复杂度要求严格(需原地排序)的场景;
  • 嵌入式系统或资源受限设备(算法简单,内存占用低)。

对于大规模数据,建议使用快速排序、归并排序等更高效的算法;若需稳定排序,可选择归并排序或基数排序。


希尔排序通过分组插入排序和逐步缩小增量的策略,有效优化了插入排序的性能,是一种兼顾简单性与效率的排序算法。其核心在于增量序列的选择,合理的增量可显著提升排序速度。尽管在极端场景下性能不及高级排序算法,但希尔排序因实现简单、空间效率高,仍是实践中常用的排序方案之一。

相关推荐
lxh01134 小时前
数组中的第K个最大元素
数据结构·算法
木尼1234 小时前
leedcode 算法刷题第三十一天
算法·leetcode·职场和发展
长安——归故李4 小时前
【modbus学习】
java·c语言·c++·学习·算法·c#
Boop_wu5 小时前
[数据结构] LinkedList
数据结构
兴科Sinco5 小时前
[leetcode 1]给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数[力扣]
python·算法·leetcode
沐怡旸5 小时前
【算法--链表】138.随机链表的复制--通俗讲解
算法·面试
anlogic5 小时前
Java基础 9.10
java·开发语言·算法
薛定谔的算法5 小时前
JavaScript单链表实现详解:从基础到实践
数据结构·算法·leetcode
CoovallyAIHub5 小时前
CostFilter-AD:用“匹配代价过滤”刷新工业质检异常检测新高度! (附论文和源码)
深度学习·算法·计算机视觉