希尔排序:突破传统排序的边界

一、算法思想

希尔排序(Shell Sort),也被叫做缩小增量排序,是插入排序的一种改进版本。希尔排序的核心在于先将整个待排序的记录序列分割成若干个子序列,分别进行直接插入排序。随着增量逐渐减小,子序列的长度慢慢增加,整个序列会变得越来越接近有序。当增量减至 1 时,整个序列就会被合并为一个,再进行一次直接插入排序,最终完成整个排序过程。

与插入排序对比

插入排序在处理部分有序的数组时效率更高,而希尔排序正是利用了这一特性。它通过分组预排序,让数组先达到部分有序的状态,最后再进行一次插入排序,从而减少了元素移动的次数。

算法步骤

  1. 选择增量序列:确定一个递减的增量序列,常用的增量序列有希尔增量(n/2, n/4, ..., 1)、Knuth 增量(3k +1)等。
  2. 按增量分组:根据当前增量将数组分成若干个子序列,每个子序列的元素间隔为当前增量。
  3. 对子序列排序:对每个子序列分别进行插入排序。
  4. 减小增量:增量逐渐减小,重复步骤 2 和 3,直到增量为 1。
  5. 最终排序:当增量为 1 时,整个数组作为一个子序列进行一次插入排序,此时数组已基本有序,插入排序效率较高。

二、手动排序示例

下面以数组 [8, 9, 1, 7, 2, 3, 5, 4, 6, 0] 为例,详细展示希尔排序的过程。这里我们采用希尔增量序列(初始增量为数组长度的一半,之后每次减半)。

初始数组

[8, 9, 1, 7, 2, 3, 5, 4, 6, 0]

第一趟排序(增量为 5)

将数组分成 5 个子序列:

  • 子序列 1:[8, 3] → 排序后 [3, 8]
  • 子序列 2:[9, 5] → 排序后 [5, 9]
  • 子序列 3:[1, 4] → 排序后 [1, 4]
  • 子序列 4:[7, 6] → 排序后 [6, 7]
  • 子序列 5:[2, 0] → 排序后 [0, 2]

排序后的数组:

[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]

第二趟排序(增量为 2)

将数组分成 2 个子序列:

  • 子序列 1:[3, 1, 0, 9, 7] → 排序后 [0, 1, 3, 7, 9]
  • 子序列 2:[5, 6, 8, 4, 2] → 排序后 [2, 4, 5, 6, 8]

排序后的数组:

[0, 2, 1, 4, 3, 5, 7, 6, 9, 8]

第三趟排序(增量为 1)

此时进行直接插入排序:

[0, 2, 1, 4, 3, 5, 7, 6, 9, 8] → [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

最终得到有序数组:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

三、C 语言实现代码

下面是希尔排序的 C 语言实现,采用希尔增量序列:

#include <stdio.h>// 希尔排序函数
void shellSort(int arr[], int n) {// 初始增量为数组长度的一半,之后每次减半,直到增量为1for (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[] = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组: \n");printArray(arr, n);shellSort(arr, n);printf("排序后的数组: \n");printArray(arr, n);return 0;
}

四、代码解释

希尔排序函数 shellSort

  1. 增量序列控制

    • 初始增量 gap 设为数组长度的一半(n/2)。
    • 每轮循环后将增量减半(gap /= 2),直到增量为 1。
  2. 分组插入排序

    • 对于每个增量 gap,将数组分为 gap 个子序列。
    • 对每个子序列进行插入排序,确保元素在各自子序列中有序。
  3. 插入排序优化

    • 使用临时变量 temp 保存当前元素。
    • 通过比较和移动元素,找到 temp 应插入的位置。

主函数 main

  1. 数组初始化:定义待排序的数组 arr
  2. 排序前输出:调用 printArray 函数显示原始数组。
  3. 调用排序:调用 shellSort 函数对数组进行排序。
  4. 排序后输出:再次调用 printArray 函数显示排序后的数组。

五、算法复杂度与稳定性

时间复杂度

希尔排序的时间复杂度与增量序列的选择有关,不同的增量序列会导致不同的时间复杂度:

  • 最坏情况:希尔增量序列下为 O (n²)
  • 平均情况:取决于增量序列,可能达到 O (n^1.3) 或更好
  • 最好情况:当数组已经有序时为 O (n)

空间复杂度

希尔排序只需要常数级的额外空间,因此空间复杂度为 O (1)。

稳定性

希尔排序是一种不稳定的排序算法,因为在不同的子序列插入排序过程中,相同元素的相对顺序可能会发生改变。

六、希尔排序的优缺点

优点

  1. 高效性:对于中等规模的数据,希尔排序的性能通常优于直接插入排序和选择排序。
  2. 空间效率:只需要常数级的额外空间。
  3. 实现简单:代码结构相对简单,易于理解和实现。

缺点

  1. 复杂度分析困难:时间复杂度依赖于增量序列的选择,难以精确分析。
  2. 不稳定性:不适合需要保持元素相对顺序的应用场景。

七、适用场景

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

  • 数据量中等且不需要稳定性的排序任务。
  • 对内存使用有限制的环境,因为它只需要 O (1) 的额外空间。
  • 作为更复杂排序算法的预处理步骤。

希尔排序通过巧妙的分组策略,打破了传统插入排序的性能瓶颈,为排序算法的发展开辟了新的思路。在实际应用中,合理选择增量序列可以显著提高希尔排序的性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88943.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88943.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka事务消息与Exactly-Once语义实战指南

Kafka事务消息与Exactly-Once语义实战指南 在分布式微服务或大数据处理场景中&#xff0c;消息队列常被用于异步解耦、流量削峰和系统伸缩。对于重要业务消息&#xff0c;尤其是金融、订单、库存等场景&#xff0c;消息的精确投递&#xff08;Exactly Once&#xff09;和事务一…

26.将 Python 列表拆分为多个小块

将 Python 列表拆分为多个小块(Chunk a List) 📌 场景 1:按份数 chunk_into_n(lst, n) 将一个列表平均拆分为 n 个块。如果不能整除,最后一块会包含剩余元素。 ✅ 示例代码 from math import ceildef chunk_into_n(lst, n):size = ceil(len

18.理解 Python 中的切片赋值

1. 切片语法回顾 标准切片语法格式为: [start_at : stop_before : step]start_at:起始索引(包含)stop_before:结束索引(不包含)step:步长(默认为 1)例如: lst = [1, 2,

论文 视黄素与细胞修复

王伟教授发布&#xff0c;通过对比兔子和老鼠耳朵穿孔后的复原&#xff0c;控制变量法发现了 视黄素对细胞修复的影响

JavaScript 的执行上下文

当 JS 引擎处理一段脚本内容的时候,它是以怎样的顺序解析和执行的?脚本中的那些变量是何时被定义的?它们之间错综复杂的访问关系又是怎样创建和链接的?要解释这些问题,就必须了解 JS 执行上下文的概念。 JavaScript引擎: JavaScript引擎是一个计算机程序,它接收JavaScri…

掉线监测-tezos rpc不能用,改为残疾网页监测

自从有了编程伴侣&#xff0c;备忘的需求变得更低了&#xff0c;明显不担心记不住语法需要记录的情景。然而还是保持习惯&#xff0c;就当写日记吧&#xff0c;记录一下自己时不时在瞎捣腾啥。tm&#xff0c;好人谁记日记。就是监控灰色各自前紧挨着出现了多少红色格子。一共查…

Spark Expression codegen

Expression codegen src/main/scala/org/apache/spark/sql/catalyst/expressions/Expression.scala def genCode(ctx: CodegenContext): ExprCode = {ctx.subExprEliminationExprs.get(ExpressionEquals(

Axios方法完成图书管理页面完整版

一、目的 需要实现的功能有包括&#xff1a; 从服务器发送请求&#xff0c;获取图书列表并渲染添加新图书编辑现有图书信息删除图书以上每一步都实现与服务器存储数据同步更改 二、基础配置 引入Axios库&#xff1a; <script src"https://cdn.jsdelivr.net/npm/ax…

SQLlite下载以及简单使用

SQLite Download Page cd D:\WK\2025\StudentManagerSystem\sqlite D: entManagerSystem\sqlite>sqlite3.exe 所建库的名字.db 一&#xff1a;命令 <1>打开某个数据库文件中 sqlite3 test.db<2>查看所有的命令介绍(英文) .help<3>退出当前数据库系统 .qu…

函数柯里化详解

一、函数柯里化&#xff1a; 是一种高阶函数技术&#xff0c;它将一个多参数函数转换为一系列单参数函数的链式调用。 核心概念 定义&#xff1a;将一个函数 f(a, b, c) 转换为 f(a)(b)© 的形式 **本质&#xff1a;**通过闭包保存参数&#xff0c;实现分步传参 关键特征&a…

C++11:constexpr 编译期性质

C11&#xff1a;constexpr & 编译期性质常量表达式 constexpr变量IiteralType函数自定义字面量参数匹配与重载规则静态断言常量表达式 constexpr const expression常量表达式&#xff0c;是C11引入的新特性&#xff0c;用于将表达式提前到编译期进行计算&#xff0c;从而减…

【每天一个知识点】多模态信息(Multimodal Information)

常用的多模态信息&#xff08;Multimodal Information&#xff09;指的是来源于多种感知通道/数据类型的内容&#xff0c;这些信息可以被整合处理&#xff0c;以提升理解、推理与生成能力。在人工智能和大模型系统中&#xff0c;典型的多模态信息主要包括以下几类&#xff1a;✅…

iOS 抓包工具精选对比:不同调试需求下的工具适配策略

iOS 抓包痛点始终存在&#xff1a;问题不是“抓不抓”&#xff0c;而是“怎么抓” 很多开发者都遇到过这样的情况&#xff1a; “接口没有返回&#xff0c;连日志都没打出来”“模拟器正常&#xff0c;真机无法请求”“加了 HTTPS 双向认证&#xff0c;抓不到了”“明明设置了 …

图像修复:深度学习实现老照片划痕修复+老照片上色

第一步&#xff1a;介绍 1&#xff09;GLCIC-PyTorch是一个基于PyTorch的开源项目&#xff0c;它实现了“全局和局部一致性图像修复”方法。该方法由Iizuka等人提出&#xff0c;主要用于图像修复任务&#xff0c;能够有效地恢复图像中被遮挡或损坏的部分。项目使用Python编程语…

css 边框颜色渐变

border-image: linear-gradient(90deg, rgba(207, 194, 195, 1), rgba(189, 189, 189, 0.2),rgba(207, 194, 195, 1)) 1;

本地 LLM API Python 项目分步指南

分步过程 需要Python 3.9 或更高版本。 安装 Ollama 并在本地下载 LLM 根据您的操作系统&#xff0c;您可以从其网站下载一个或另一个版本的 Ollama 。下载并启动后&#xff0c;打开终端并输入以下命令&#xff1a; ollama run llama3此命令将在本地拉取&#xff08;下载&…

日本的所得税计算方式

✅ 【1】所得税的计算步骤&#xff08;概要&#xff09; 日本的所得税大致按照以下顺序来计算&#xff1a; 1️⃣ 统计收入&#xff08;销售额、工资等&#xff09; 2️⃣ 扣除必要经费等&#xff0c;得到「所得金額」 3️⃣ 扣除各类「所得控除」&#xff08;所得扣除&#xf…

【langchain4j篇01】:5分钟上手langchain4j 1.1.0(SpringBoot整合使用)

目录 一、环境准备 二、创建项目、导入依赖 三、配置 application.yml 四、注入Bean&#xff0c;开箱即用 五、日志观察 一、环境准备 首先和快速上手 Spring AI 框架一样的前置条件&#xff1a;先申请一个 apikey &#xff0c;此部分步骤参考&#xff1a;【SpringAI篇01…

js运算符

运算符 jarringslee*赋值运算符 - / 对变量进行赋值的运算符&#xff0c;用于简化代码。左边是容器&#xff0c;右边是值一元运算符正号 符号- 赋予数据正值、负值自增 自减– 前置和后置&#xff1a;i和i&#xff1a;一般情况下习惯使用后置i&#xff0c;两者在单独…

next.js 登录认证:使用 github 账号授权登录。

1. 起因&#xff0c; 目的: 一直是这个报错。2. 最终效果&#xff0c; 解决问题&#xff0c;能成功登录、体验地址&#xff1a;https://next-js-gist-app.vercel.app/代码地址&#xff1a; https://github.com/buxuele/next-js-gist-app3. 过程: 根本原因: github 的设置&…