写在前边

大家好,我是melo,一名大二上软件工程在读生,经历了一年的摸滚,现在已经在工作室里边准备开发后台项目啦。

不过这篇文章呢,还是想跟大家聊一聊数据结构与算法,学校也是大二上才开设了数据结构这门课,希望可以一边学习数据结构一边积累后台项目开发经验。

最近我们进入了排序算法专题,上节课聊到了"简单"插入排序,那在简单的基础上,我们可以怎么做进一步的优化呢,这篇来看看优化版--希尔排序

知识点

概念

希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进。

希尔排序又称缩小增量排序,因 DL.hell 于 1959 年提出而得名。

它通过比较相距一定间隔的元素来进行,各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止。

引入

简单插入排序存在问题

改进

  • 分割待排序记录的个数,分别进行插入排序

基本思想

  • 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个数组恰被分成一组,算法便终止

精髓

  • 由于开始时每组只有很少整数,所以排序很快。之后每组含有的整数越来越多,但是由于这些数也越来越有序,所以排序速度也很快。

示意图

按一定增量分组,然后逐渐减小增量

初始化gap为length/2,逐渐减小为gap/2,直到gap不满足>0的条件

分组后,再对该组进行简单插入排序

  • 拿图中的第三步举例,数组分成了两组[3,1,0,9,7],[5,6,8,4,2]

    • 对[3,1,0,9,7]进行简单插入排序,看成前n-1个为有序数组,第n个为待插入的元素(找到自己的位置后插入即可)

不够清晰的话也可以看下边这张



代码实现

力扣912排序数组 : https://leetcode-cn。com/problems/sort-an-array/submissions/

又是这道题hhh,万能

思路概览

首先

  • 我们要先初始化增量gap=length/2,然后不断缩小gap=gap/2 直到不满足gap>0

所以我们最外层会需要一个for循环来调控这个gap的变化

其次,再往内层走

  • 对于分组后,由于我们是要对分组后的每一组进行简单插入排序,而插入排序我们默认从待排序数组的第二位开始,所以我们需要从每一组的第二位开始去遍历,直到整个数组的末尾

for循环让i=gap;i<数组;i++即可

最后,就对该数组进行插入排序即可

  • 注意不是跟前一个进行比较了,而是跟 j-gap 比较

最初版本(for)

for的话,我是先把j赋值等于i-gap,这样的话就是跟j去比较,最后也还会去j-=gap

会导致我最后跳出循环的时候,得插到j+gap

/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* sortArray(int* nums, int numsSize, int* returnSize){
//逐步缩小增量gap
for(int gap=numsSize/2;gap>0;gap=gap/2){
int insertValue = 0;
int j;
//从分组后的第一组的第二位开始
for(int i=gap;i<numsSize;i++){
//保存待插入的值
insertValue=nums[i];
//因为本身有序,若待插入的数还大于最后一个数,则无须继续遍历下去了
//注意j>=0的条件,这里无哨兵了
for(j=i-gap;j>=0 && insertValue<nums[j];j-=gap){
//若待插入的值小于索引值,证明要索引值需要后移,空出j这个位置给插入值
nums[j+gap]=nums[j];
}
//跳出循环后,把这个数插入到指定位置
nums[j+gap]=insertValue;
}
}
*returnSize=numsSize;
return nums;
}

改进for

先去判断是否 j-gap>=0,满足才进循环,才会去j-=gap,所以最后j就是要插入的位置

/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* sortArray(int* nums, int numsSize, int* returnSize){
//逐步缩小增量gap
for(int gap=numsSize/2;gap>0;gap=gap/2){
int insertValue = 0;
//用于插入排序中遍历待排序的数组
int j;
//从分组后的第一组的第二位开始
for(int i=gap;i<numsSize;i++){
//保存待插入的值
insertValue=nums[i];
//因为本身有序,若待插入的数还大于最后一个数,则无须继续遍历下去了
for(j=i;j-gap>=0 && insertValue<nums[j-gap];
j-=gap){
//若待插入的值小于索引值,证明要索引值需要后移,空出j这个位置给插入值
nums[j]=nums[j-gap];
}
//跳出循环后,把这个数插入到指定位置
nums[j]=insertValue;
}
}
*returnSize=numsSize;
return nums;
}

注意

  • 希尔排序没有办法用到哨兵了,我们需要注意判断是否走到头了

参考

  • 菜鸟教程
  • 尚硅谷数据结构与算法

"简单"的优化--希尔排序也没你想象中那么难的更多相关文章

  1. 【PHP数据结构】插入类排序:简单插入、希尔排序

    总算进入我们的排序相关算法的学习了.相信不管是系统学习过的还是没有系统学习过算法的朋友都会听说过许多非常出名的排序算法,当然,我们今天入门的内容并不是直接先从最常见的那个算法说起,而是按照一定的规则一 ...

  2. Fragment中监听onKey事件,没你想象的那么难。

    项目中越来越多的用到Fragment,在用Fragment取代TabHost的时候遇到了一个问题,我们都知道,TabHost的Tab为Activity实例,有OnKey事件,但是Fragment中没有 ...

  3. php六种基础算法:冒泡,选择,插入,快速,归并和希尔排序法

    $arr(1,43,54,62,21,66,32,78,36,76,39); 1. 冒泡排序法  *     思路分析:法如其名,就是像冒泡一样,每次从数组当中 冒一个最大的数出来.  *     比 ...

  4. 算法(第四版)学习笔记之java实现希尔排序

    希尔排序思想:使数组中随意间隔为h的元素都是有序的. 希尔排序是插入排序的优化.先对数组局部进行排序,最后再使用插入排序将部分有序的数组排序. 代码例如以下: /** * * @author seab ...

  5. 数据结构和算法(Golang实现)(22)排序算法-希尔排序

    希尔排序 1959 年一个叫Donald L. Shell (March 1, 1924 – November 2, 2015)的美国人在Communications of the ACM 国际计算机 ...

  6. 【PHP数据结构】其它排序:简单选择、桶排序

    这是我们算法正式文章系列的最后一篇文章了,关于排序的知识我们学习了很多,包括常见的冒泡和快排,也学习过了不太常见的简单插入和希尔排序.既然今天这是最后一篇文章,也是排序相关的最后一篇,那我们就来轻松一 ...

  7. c++实现排序(简单插入,希尔,选择,快速,冒泡,堆排)

    简单插入排序 适用于记录较少且基本有序的记录.算法思想:给定一个存在分界线的序列,分界线左边有序,右边无序,依次将右边的没排序的数与左边序列进行比较,插入相应位置,再对分界线做出相应调整,下面用图来说 ...

  8. 常见排序算法总结:插入排序,希尔排序,冒泡排序,快速排序,简单选择排序以及java实现

    今天来总结一下常用的内部排序算法.内部排序算法们需要掌握的知识点大概有:算法的原理,算法的编码实现,算法的时空复杂度的计算和记忆,何时出现最差时间复杂度,以及是否稳定,何时不稳定. 首先来总结下常用内 ...

  9. Python实现八大排序(基数排序、归并排序、堆排序、简单选择排序、直接插入排序、希尔排序、快速排序、冒泡排序)

    目录 八大排序 基数排序 归并排序 堆排序 简单选择排序 直接插入排序 希尔排序 快速排序 冒泡排序 时间测试 八大排序 大概了解了一下八大排序,发现排序方法的难易程度相差很多,相应的,他们计算同一列 ...

随机推荐

  1. Django3.2边学边记—Adimn站点管理

    准备工作 创建管理员的用户名和密码: python manage.py createsuperuser 根据提示创建用户名 密码 在admin.py中注册模型类 from django.contrib ...

  2. Python项目生成requirements.txt文件之pipreqs的使用

    生成requirements.txt时使用pip freeze > requirements.txt会将环境下所有的安装包都进行生成,再进行安装的时候会全部安装很多没有的包.耗时耗力其实是不可取 ...

  3. P2490-[SDOI2011]黑白棋【博弈论,dp】

    正题 题目链接:https://www.luogu.com.cn/problem/P2490 题目大意 一个长度为\(n\)的棋盘上放下\(k\)个棋子. 第一个要是白色,下一个要是黑色,在下一个是白 ...

  4. P5540-[BalkanOI2011]timeismoney|最小乘积生成树【最小生成树,凸壳】

    正题 题目链接:https://www.luogu.com.cn/problem/P5540 题目大意 给出\(n\)个点\(m\)条边边权是一个二元组\((a_i,b_i)\),求出一棵生成树最小化 ...

  5. Python编码规范(养成好的编码习惯很重要)

    学习过程养成良好的编码习惯 1. 类名采用驼峰命名法,即类名的每个首字母都大写,如:class HelloWord,类名不使用下划线 2. 函数名只使用小写字母和下划线 3.定义类后面包含一个文档字符 ...

  6. 你需要知道的MySQL&InnoDB锁都在这里

    目录 一.前言 二.锁的类型 2.1 全局锁 2.2 表级锁 2.2.1 表锁 2.2.2 元数据锁(Meta Data Locks) 2.2.3 自增列锁(AUTO-INC Locks) 2.2.4 ...

  7. Asp.Net Core 中的HTTP协议详解

    1.前言 好久没写博客了,最近虽然没什么假期,但是却比以前还忙!工作.工作.工作,就像赶集似的,聚在一起.对于Web开发人员来说,深入了解HTTP有助于我们开发出更好.更高的Web应用程序.当应用程序 ...

  8. HPE ProLiant 系列服务器Microsoft Windows 2008 R2系统下网卡绑定方法

    HPE Network Configuration Utility(以下简称NCU) 网卡绑定工具,用户可以通过该工具很方便的把服务器的多个网卡捆绑到一起以达到容错和增加可用带宽的目的. 1.打开NC ...

  9. gin 跨域问题

    package middlewares import ( "github.com/gin-gonic/gin" "net/http" ) func Cors() ...

  10. iOS自定义拍照框拍照&裁剪(一)

    卡片机时代 很重要的一点是,相机本身是没有方向概念的,它不理解拍摄的内容,只会以相机自己的坐标系去保存数据,下图展示了相机对"F"进行四个角度拍摄时返回的图片数据. 最初的卡片机时 ...