数据结构——排序算法——希尔排序

news/2025/1/12 17:41:55/

希尔排序本质上是对插入排序的一种优化,它利用了插入排序的简单,又克服了插入排序每次只交换相邻两个元素的缺点。它的基本思想是:

1.将待排序数组按照一定的间隔分为多个子数组,每组分别进行插入排序。这里按照间隔分组指的不是取连续的一段数组,而是每跳跃一定间隔取一个值组成一组
2.逐渐缩小间隔进行下一轮排序
3.最后一轮时,取间隔为 1,也就相当于直接使用插入排序。但这时经过前面的「宏观调控」,数组已经基本有序了,所以此时的插入排序只需进行少量交换便可完成。

举个例子,对数组 [84,83,88,87,61,50,70,60,80,99]进行希尔排序的过程如下:

请添加图片描述
1.第一遍(5 间隔排序):按照间隔 5 分割子数组,共分成五组,分别是[84,50],[83,70],[88,60],[87,80],[61,99]。对它们进行插入排序,排序后它们分别变成: [50,84],[70,83],[60,88],[80,87],[61,99],此时整个数组变成 [50,70,60,80,61,84,83,88,87,99]

2.第二遍(2 间隔排序):按照间隔2 分割子数组,共分成两组,分别是 [50,60,61,83,87],[70,80,84,88,99]。对他们进行插入排序,排序后它们分别变成:[50,60,61,83,87],[70,80,84,88,99],此时整个数组变成 [50,70,60,80,61,84,83,88,87,99]。这里有一个非常重要的性质:当我们完成 2 间隔排序后,这个数组仍然是保持 5 间隔有序的。也就是说,更小间隔的排序没有把上一步的结果变坏

3.第三遍(1 间隔排序,等于直接插入排序):按照间隔 1 分割子数组,分成一组,也就是整个数组。对其进行插入排序,经过前两遍排序,数组已经基本有序了,所以这一步只需经过少量交换即可完成排序。排序后数组变成[50,60,61,70,80,83,84,87,88,99],整个排序完成。

 void shellSort(vector<int> arr) {// 间隔序列,在希尔排序中我们称之为增量序列for (int gap = arr.size() / 2; gap > 0; gap /= 2) {// 分组for (int groupStartIndex = 0; groupStartIndex < gap; groupStartIndex++) {// 插入排序for (int currentIndex = groupStartIndex + gap; currentIndex < arr.size(); currentIndex += gap) {// currentNumber 站起来,开始找位置int currentNumber = arr[currentIndex];int preIndex = currentIndex - gap;while (preIndex >= groupStartIndex && currentNumber < arr[preIndex]) {// 向后挪位置arr[preIndex + gap] = arr[preIndex];preIndex -= gap;}// currentNumber 找到了自己的位置,坐下arr[preIndex + gap] = currentNumber;}}}
}

优化

 void shellSort(vector<int> arr) {// 间隔序列,在希尔排序中我们称之为增量序列for (int gap = arr.size() / 2; gap > 0; gap /= 2) {// 从 gap 开始,按照顺序将每个元素依次向前插入自己所在的组for (int i = gap; i < arr.size(); i++) {// currentNumber 站起来,开始找位置int currentNumber = arr[i];// 该组前一个数字的索引int preIndex = i - gap;while (preIndex >= 0 && currentNumber < arr[preIndex]) {// 向后挪位置arr[preIndex + gap] = arr[preIndex];preIndex -= gap;}// currentNumber 找到了自己的位置,坐下arr[preIndex + gap] = currentNumber;}}
}

使用 Knuth 序列进行希尔排序的代码

void shellSortByKnuth(vector<int> arr) {// 找到当前数组需要用到的 Knuth 序列中的最大值int maxKnuthNumber = 1;while (maxKnuthNumber <= arr.size() / 3) {maxKnuthNumber = maxKnuthNumber * 3 + 1;}// 增量按照 Knuth 序列规则依次递减for (int gap = maxKnuthNumber; gap > 0; gap = (gap - 1) / 3) {// 从 gap 开始,按照顺序将每个元素依次向前插入自己所在的组for (int i = gap; i < arr.size(); i++) {// currentNumber 站起来,开始找位置int currentNumber = arr[i];// 该组前一个数字的索引int preIndex = i - gap;while (preIndex >= 0 && currentNumber < arr[preIndex]) {// 向后挪位置arr[preIndex + gap] = arr[preIndex];preIndex -= gap;}// currentNumber 找到了自己的位置,坐下arr[preIndex + gap] = currentNumber;}}
}

http://www.ppmy.cn/news/1107822.html

相关文章

Retinexformer 论文阅读笔记

Retinexformer: One-stage Retinex-based Transformer for Low-light Image Enhancement 清华大学、维尔兹堡大学和苏黎世联邦理工学院在ICCV2023的一篇transformer做暗图增强的工作&#xff0c;开源。文章认为&#xff0c;Retinex的 I R ⊙ L IR\odot L IR⊙L假设干净的R和L&…

代码随想录算法训练营Day43 | 动态规划(5/17) LeetCode 1049. 最后一块石头的重量 II 494. 目标和 474.一和零

动态规划第五天&#xff0c;加油&#xff01; 第一题 1049. Last Stone Weight II You are given an array of integers stones where stones[i] is the weight of the ith stone. We are playing a game with the stones. On each turn, we choose any two stones and smash…

Verilog零基础入门(边看边练与测试仿真)-时序逻辑-笔记(4-6讲)

文章目录 第四讲第五讲第六讲 第四讲 1、计数器 代码&#xff1a; //计数器 timescale 1ns/10ps module counter(clk,res,y); input clk; input res; output[7:0] y;reg[7:0] y; wire[7:0] sum;//1运算的结果&#xff08;1&#xff0…

第五章 Linux常用应用软件

第五章 Linux常用应用软件 ​ Ubuntu包含了日常所需的常用程序&#xff0c;集成了跨平台的办公套件LibreOffice和Mozila Firefox浏览器等。还提供了文本处理工具、图片处理工具等。 1.LibreOffice ​ LibreOffice免费开源&#xff0c;遵照GPL分发源代码&#xff0c;与OpenOf…

Vue通过ref修改 <el-input-number> 增减按钮的样式

Vue 为一个 <el-input-number> 设置了ref为‘inputNumberRef’, 通过这个ref获取<el-input-number>组件中的增、减按钮所在的<i>标签&#xff0c;并将它们的class分别改为el-icon-plus 和 el-icon-minus。 可以通过以下代码实现&#xff1a; <template&g…

python execute() 使用%s 拼接sql 避免sql注入攻击 好于.format

1 execute(参数一:sql 语句) # 锁定当前查询结果行 cursor.execute("SELECT high, low, vol FROM table_name WHERE symbol %s FOR UPDATE;"% (symbol,)) 2 .format() cursor.execute("SELECT high, low, vol FROM table_name WHERE symbol {} FOR UPDATE;…

JAVA8接口使用问题

JAVA8接口使用问题 文章目录 JAVA8接口使用问题1、默认方法冲突问题&#xff08;1&#xff09;亲爹优先原则&#xff08;2&#xff09;左右为难 2、常量冲突问题 1、默认方法冲突问题 &#xff08;1&#xff09;亲爹优先原则 当一个类&#xff0c;既继承一个父类&#xff0c;…

关于c语言二级指针和指针指向数组

写这篇文章是最近碰到了这两道题目&#xff1a; #include <stdio.h>int k7;void f(int **s){ int *t&k ;*st;printf("%d,%d,%d,",k,*t,**s);}main(){ int i3,*p&i,**r &p ;f(r); printf("%d,%d,%d\n", i,*p,**r);}结果&#xff1a;7,7…