写在前边

大家好,我是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. 浏览器+css基础+选择器+权重+匹配规则

    浏览器的组成: shell+内核 shell:用户能看得到的界面就叫shell 内核:渲染rendering引擎和js引擎 现在主流拥有自己开发内核的浏览器:opera现在属于360和昆仑万维 CSS ...

  2. django使用celery搭配redis配置定时任务

    已经安装环境: Python3.6 django==2.1.8(用2.2.2需要升级sqlite3) 项目名称:ceshiproject   APP名称:ceshi 第一步:centos7下首先安装r ...

  3. P4424-[HNOI/AHOI2018]寻宝游戏【结论】

    正题 题目链接:https://www.luogu.com.cn/problem/P4424 题目大意 \(n\)个\(m\)位二进制数,开始是一个\(0\). 然后依次对所有二进制数进行\(n\)次 ...

  4. Hive语法及其进阶(二)

    1.使用JDBC连接Hive 1 import java.sql.Connection; 2 import java.sql.DriverManager; 3 import java.sql.Prep ...

  5. gcc、g++、gdb安装

    Windows安装 有闲工夫在Windows上安装g++/gcc/gdb,还不如装个虚拟机安装Linux,在Linux上安装 但是我还是要讲的 首先,需要安装MinGW,MinGW,是Minimali ...

  6. Java多线程--实现同步的9种方法

    我们通常说的保持同步,其实就是对共享资源的保护.在单线程模型中, 我们永远不用担心"多个线程试图同时使用同一个资源的问题", 但是有了并发, 就有可能发生多个线程竞争同一个共享资源 ...

  7. 树莓派3B搭建NODE-RED运行环境并构建数据流

    树莓派3B搭建NODE-RED运行环境并构建数据流 树莓派搭建Node-RED环境 树莓派自2015年开始是默认就带NODE-RED的,但是如今已是2018年:)自带的版本已经很老了,可通过下面的命令 ...

  8. mysql order by语句流程是怎么样的

    order by流程是怎么样的 注意点: select id, name,age,city from t1 where city='杭州' order by age limit 1000; order ...

  9. Java序列初始化

    1.数组 Java数组可以用元素集合初始化: char[] c=new char[]{'.','.','.','.'}; 而想要用指定数量的相同元素来初始化数组,可以使用Arrays.fill()方法 ...

  10. Spring Security 多过滤链的使用

    Spring Security 多过滤链的使用 一.背景 二.需求 1.给客户端使用的api 2.给网站使用的api 三.实现方案 方案一: 方案二 四.实现 1.app 端 Spring Secur ...