当前位置: 首页 > news >正文

希尔排序。

一、希尔排序简介

希尔排序是插入排序的一种高效改进版本,也称为"缩小增量排序"(Diminishing Increment Sort)。它由D.L.Shell于1959年提出,是直接插入排序算法的优化版本。

特点

  • 非稳定排序算法(相同元素的相对位置可能改变)
  • 时间复杂度:平均O(n^1.3),最坏O(n^2)
  • 空间复杂度:O(1)(原地排序)

二、希尔排序基本原理

希尔排序的核心思想是:将待排序的序列按照一定的"增量"(gap)分成若干个子序列,对每个子序列分别进行插入排序。然后逐渐减小增量,重复这个过程,直到增量为1时,整个序列基本有序,最后进行一次插入排序完成排序。

为什么有效?

  1. 插入排序在处理几乎有序的数据时效率很高(接近O(n))
  2. 但插入排序每次只能移动一位,效率较低
  3. 希尔排序通过"大步长"排序,使数据快速接近有序状态,再用小步长进行精细调整

三、希尔排序的步骤

  1. 选择一个增量序列(通常从n/2开始,每次减半,直到1)
  2. 按照当前增量,将数组分成若干组
  3. 对每组进行直接插入排序
  4. 缩小增量,重复步骤2-3
  5. 当增量为1时,整个数组基本有序,进行一次插入排序完成排序

四、实现

#include <stdio.h>// 希尔排序函数
void shellSort(int arr[], int n) {// 初始增量为数组长度的一半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(int arr[], int n) {for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int arr[] = {49, 38, 65, 97, 76, 13, 27, 49, 55, 4};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组:");printArray(arr, n);shellSort(arr, n);printf("希尔排序后:");printArray(arr, n);return 0;
}

五、代码详解

1. 增量序列的确定

for (int gap = n / 2; gap > 0; gap /= 2)
  • 初始增量取数组长度的一半(n/2)
  • 每次循环后,增量减半(gap /= 2)
  • 直到增量变为0(当n=1时,gap=0.5,整数除法后为0)

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;
}
  • 从第一个增量位置开始遍历
  • 将当前元素与前面的元素比较(间隔为gap)
  • 将比当前元素大的元素向后移动
  • 找到合适位置后插入当前元素

六、希尔排序示例(详细步骤)

假设待排序数组:[49, 38, 65, 97, 76, 13, 27, 49, 55, 4]

初始增量:gap = 10/2 = 5

第一轮(gap=5):

将数组分成5个子序列:

  • 子序列1: [49, 13] → 排序后: [13, 49]
  • 子序列2: [38, 27] → 排序后: [27, 38]
  • 子序列3: [65, 49] → 排序后: [49, 65]
  • 子序列4: [97, 55] → 排序后: [55, 97]
  • 子序列5: [76, 4] → 排序后: [4, 76]

排序后数组:[13, 27, 49, 55, 4, 49, 38, 65, 97, 76]

第二轮(gap=2):

将数组分成2个子序列:

  • 子序列1: [13, 49, 4, 65, 97] → 排序后: [4, 13, 49, 65, 97]
  • 子序列2: [27, 55, 49, 38, 76] → 排序后: [27, 38, 49, 55, 76]

排序后数组:[4, 27, 13, 38, 49, 49, 55, 65, 97, 76]

第三轮(gap=1):

整个数组进行一次插入排序,得到最终有序数组: [4, 13, 27, 38, 49, 49, 55, 65, 76, 97]

七、希尔排序特点

优点:

  1. 比直接插入排序效率高,尤其在数据量较大时
  2. 原地排序,空间复杂度低(O(1))
  3. 实现相对简单

缺点:

  1. 非稳定排序算法
  2. 增量序列的选择对性能影响较大
  3. 最坏情况时间复杂度仍为O(n^2)
http://www.dtcms.com/a/361231.html

相关文章:

  • 关于命名参数占位符的分析(主要以PHP为例)
  • 详细介绍 JMeter 性能测试
  • Java泛型通配符详解:搞懂?/extends/super用法,避开集合操作踩坑点
  • 快递地址归类排序实现(Java Python)
  • Jenkins 自动构建Vue 项目的一个大坑
  • JVM核心机制:类加载与内存结构详解
  • OpenHarmony智能语音框架深度拆解:从VAD到唤醒词打造你的AI语音智能体
  • 自动化软件测试工具Parasoft C/C++test如何实现运行时错误的检测与修复
  • 面试经典150题[021]:反转字符串中的单词(LeetCode 151)
  • 【XR技术概念科普】VST(视频透视)vs OST(光学透视):解码MR头显的两种核心技术路径
  • 「数据获取」《中国住户调查年鉴》(2000-2024)(获取方式看绑定的资源)
  • SQLark:一款面向信创应用开发者的数据库开发和管理工具
  • Jmeter实现参数化的4种方式
  • Windows神器,按键屏蔽
  • 【机器学习学习笔记】pandas基础
  • (纯新手教学)计算机视觉(opencv)实战十二——模板匹配(cv2.matchTemplate)
  • UE角色取消被Decal影响
  • Jetson AGX Orin平台R36.3.0版本1080P25fps MIPI相机图像采集异常调试记录
  • 基于单片机电动车充电桩/充电车棚环境监测设计
  • 基于RS-485接口的芯片的FPGA驱动程序
  • 吴恩达机器学习作业十二:协同过滤(电影推荐系统)
  • 广电手机卡到底好不好?
  • Git基础使用和PR贡献
  • .Net程序员就业现状以及学习路线图(二)
  • Android面试指南(六)
  • 大模型落地全流程实践:从技术选型到企业级部署
  • 音视频开发入门:FFmpeg vs GStreamer,新手该如何选择?
  • 松灵斯坦福Mobile ALOHA同款 | 通过低成本全身远程操作实现双手机器人移动操控学习
  • 01数据结构-红黑树
  • 永磁同步电机无速度算法--高频脉振方波注入法(测量轴系转子位置误差信号解耦处理)