1、希尔排序基本思路:

之前的一篇博客中,介绍了直接插入排序的实现,希尔排序实际上是在直接插入排序的基础上优化

当一组数据,越接近有序,那么他需要调整(移动)的次数就越少

(往极端的方向想,如果一组数据是有序的,那么根本就无需排序)

||

\ || /

V

希尔排序的思路:

(1)先通过分组预排序,让一组数据接近有序

(2)再通过直接插入排序,将这组数据重新排序

2、代码实现

下面介绍的顺序是:

(a)先分组

(b)以红组为例,实现调整过程

(c)三个组预排序的整体实现

(三组同时排序,红组排一次,绿组排一次,紫组排一次,然后又回到红组)

(d)直接插入排序

(1)分组

我们使用抽取的方法来将一组数据进行分组,抽取的间隔gap = 3

这样就分成了 红组、绿组、紫组

(2)以红组为例进行排序

调整的方式和直接插入排序的方式 几乎一样,但是需要注意的是,end每次移动的距离是 gap,

而不是1

void ShellSort(int* a, int size, int gap)
{int end = 0;int val = a[end + gap];         //第一个注意点:end的下一个位置在 end+gapwhile (end>=0){if (a[end] > val){a[end + gap] = a[end];     //第二个注意点end -= gap;                //第三个注意点:end向前移动的时候,移动gap个单位}else{break;}}a[end + gap] = val;               //第四个注意点
}

(3)三组预排序

这里需要注意的两个地方是

(a)每个组的起始位置是连续的

(b)end最远能到达的位置只能是8所在的位置,即 size-1-gap 的位置

void ShellSort(int* a, int size, int gap)
{for (size_t i = 0; i < size-1-gap; i++){int end = i;                        //end的起始位置是连续的int val = a[end + gap];         //第一个注意点:end的下一个位置在 end+gapwhile (end >= 0){if (a[end] > val){a[end + gap] = a[end];       //第二个注意点end -= gap;                //第三个注意点:end向前移动的时候,移动gap个单位}else{break;}}a[end + gap] = val;               //第四个注意点}
}

(4)直接插入排序

经过预排序后,这组数据更加接近有序,将这组数据送入直接插入排序即可

直接插入排序函数我们使用之前博客写好的选择排序——直接插入排序_challenglistic的博客-CSDN博客1、基本思想(1)想象 3的前面是一个空的有序数组(2)先将3 放入这个有序数组,然后从第2个元素开始,逐个和有序数组中的元素 排序横向:插入新的元素后,有序数组的自我调整纵向:有序数组调整完毕,有序数组多一位成员(3)直到end到达第 size-1 位size:数组元素的个数2、代码实现(1)单次有序数组的调整过程假设 以end = 2的调整为例int end = 2;int val = a[end + 1...https://blog.csdn.net/challenglistic/article/details/123396468?spm=1001.2014.3001.5501

void InsertSort(int* a,int size)
{for (size_t i = 0; i < size-1; i++){int end = i;int val = a[end + 1]; //事先记录下每次要插入的数while (end >= 0){if (a[end] > val){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = val;       //end = -1时,会跳出循环,说明有序数组中的所有元素都比val要小}
}void ShellSort(int* a, int size, int gap)
{/*************************预排序********************************/for (size_t i = 0; i < size-1-gap; i++){int end = i;                      //end的起始位置是连续的int val = a[end + gap];         //第一个注意点:end的下一个位置在 end+gapwhile (end >= 0){if (a[end] > val){a[end + gap] = val;      //第二个注意点end -= gap;                //第三个注意点:end向前移动的时候,移动gap个单位}else{break;}}a[end + gap] = val;               //第四个注意点}/*************************直接插入排序****************************/InsertSort(a,size);}

3、结果测试

int main() {int arr[] = { 3,5,2,6,1,7,4,8,12,10,11,9,15,14,13 };int gap = 3;ShellSort(arr, sizeof(arr) / sizeof(arr[0]), gap);for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}

​​​​​​​

4、预排序优化

预排序的时候,我们设置gap = 3,我们测试一下指针的移动次数

(1)gap与预排序的联系:

gap越大,预排序越快,但是 越不有序

gap越小,预排序越慢,但是 越有序

(2)思路

我们可以多次预排序,每次预排序结束,gap = gap/2,直到gap = 1

gap较大的时候,预排序很快

随着gap减小,虽然慢,但更接近有序

(3)代码实现

我们将gap的初始值设置为size,每经过一次预排序,gap除以2

直到gap = 1(直接插入排序)

void ShellSort(int* a, int size)
{int gap = size / 2;while (gap>1){gap /= 2;for (size_t i = 0; i <= size - 1 - gap; i++){int end = i;                       //end的起始位置是连续的int val = a[end + gap];         //第一个注意点:end的下一个位置在 end+gapwhile (end >= 0){if (a[end] > val){a[end + gap] = a[end];       //第二个注意点end -= gap;                //第三个注意点:end向前移动的时候,移动gap个单位p++;}else{break;}}a[end + gap] = val;             //第四个注意点}}  InsertSort(a, size);
}

(4)代码测试结果

排序的个数比较少的时候,前后gap的设置方法没有特别明显的差异

5、时间复杂度

希尔排序的时间复杂度计算十分复杂,这里就直接给出结果

希尔排序的移动次数和gap有关,平均移动次数是 N^1.3

时间复杂度接近 O(N)

选择排序(二)——希尔排序相关推荐

  1. 排序算法:冒泡排序、插入排序、选择排序、希尔排序

    相关博客: 排序算法:冒泡排序.插入排序.选择排序.希尔排序 排序算法:归并排序.快速排序 排序算法:桶排序.计数排序.基数排序 排序算法:堆排序 十大排序算法小结 一.冒泡排序: 1.算法原理: 冒 ...

  2. 冒泡排序、插入排序、选择排序、希尔排序、堆排序、归并排序等常用排序算法的比较

    掌握好常用的排序算法,在实际的项目开发中可以节省很多的时间.每一种排序算法在执行的效率上是存在差别的,这些微小的时间差,也许在平常的联系当中感觉不到,但是涉及到数据量比较大或者是在资源比较紧张的系统中 ...

  3. 【排序算法】冒泡排序|选择排序|插入排序|希尔排序

    文章目录 冒泡排序 选择排序 插入排序 希尔排序 冒泡排序   第一个元素开始向第二个元素比较,若大于则交换位置,不大于则不动.然后第二个元素和第三个元素比较,再然后第三个元素和第四个元素比较-一直比 ...

  4. java语言冒泡排序法_Java实现八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序等...

    本文实现了八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序 首先是EightAlgorithms.java文件,代码如下: import jav ...

  5. 【Java】八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序 、快速排序、归并排序、堆排序和LST基数排序

    这篇文章主要介绍了Java如何实现八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序,需要的朋友可以参考下 本文实现了八个常用的排序算法:插入排序 ...

  6. c++语言编程希尔排序法排序,经典四讲贯通C++排序之二 希尔排序

    我们都知道C++排序方法中,有四种常用方法插入排序.希尔排序.交换排序以及选择排序.上一篇文章,我们介绍了插入排序,今天我们介绍另一种排序方法――希尔排序.(本系列文章统一 测试程序) 希尔排序 前面 ...

  7. 经典排序算法 - 希尔排序Shell sort

    经典排序算法 - 希尔排序Shell sort 希尔排序Shell Sort是基于插入排序的一种改进,同样分成两部分, 第一部分,希尔排序介绍 第二部分,如何选取关键字,选取关键字是希尔排序的关键 第 ...

  8. 排序算法——希尔排序的图解、代码实现以及时间复杂度分析

    希尔排序(Shellsort) 希尔排序是冲破二次时间屏障的第一批算法之一. 希尔排序通过比较相距一定间隔的元素来工作:各躺比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止.由 ...

  9. python排序算法——希尔排序(附代码)

    python排序算法--希尔排序 文章目录 python排序算法--希尔排序 一.前言 二.算法描述 三.代码实现 总结 一.前言 相关知识来自<python算法设计与分析>.初级排序算法 ...

  10. 希尔排序python 简书_排序:希尔排序(算法)

    文 | 莫若吻 (注:如果想更好的理解希尔排序,请先看看我的上一篇博客插入排序,希望会对你有帮助.) 一.简介 希尔排序(Shell Sort)是插入排序的一种算法,是对直接插入排序的一个优化,也称缩 ...

最新文章

  1. SAP WM中阶之LT25确认Group中的TO单据
  2. oracle 数据导入导出
  3. MQ对比之RabbitMQ Redis
  4. 网易云音乐:基于分布式图学习的推荐系统优化之路
  5. Hadoop - UDF
  6. 如何处理SAP Launchpad上tile打不开的问题
  7. PHP解决http和https跨域,php中http与https跨域共享session的解决方法
  8. Java读源代码学设计模式:适配器Adapter
  9. Linux内存管理:TLB flush操作
  10. Java中如何循环删除一个集合(如List)中的多个元素
  11. Ubuntu的超宽屏支持2560*1080
  12. SQL中的Having与Where的区别(面试常问)
  13. win7下linux 双系统安装教程,【系统安装】双系统——Win7下安装linux系统详细步骤...
  14. 文本数据标注工具Doccano
  15. HTML5期末大作业:绿色特产商城网站设计——绿色特产商城购物网(11页) HTML+CSS+JavaScript 网页设计作业,网页制作作业, 学生网页作业, 网页作业成品, 网页作业模板
  16. Java NIO初试
  17. js 按拼音 首字母 排序 并分组
  18. HTML5树叶飘落动画
  19. 斧劈互联网(一):企业邮箱那点事儿
  20. ff7的全部青魔法获得

热门文章

  1. 【MARK】个人装机软件备份(上)
  2. 回归一年,诺基亚只能手机销量未达千万,需要改变策略
  3. opencvsharp 使用knn 实现身份证号码识别
  4. AVERAGEX函数丨移动平均
  5. 银行软件测试岗位待遇怎么样,银行软件测试岗位职责
  6. 【精简推导】支持向量机(拉格朗日乘子法、对偶函数、KKT条件)
  7. 电子产品使用感受之--Windows 10 小米笔记本Air HDMI转VGA无信号问题
  8. Python中数组堆叠(stack)
  9. apache负载均衡 健康检查_Apache服务器配置负载均衡的方法 - Apache - 数安时代(GDCA)SSL证书官网...
  10. ​实力证明赢在起跑线:小学生开发AI识别危险文具应用