写在前边

大家好,我是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. 5. Longest Palindromic Substring
  2. Mysql5.0以上 手工注入
  3. Install SQLite
  4. Java 8 Lambda表达式
  5. JavaScript 隐式转换
  6. TreeView递归绑定数据的两种方法
  7. 第二次作业第2题_JH
  8. TUXEDO管理命令总结
  9. LeetCode_Interleaving String
  10. mysql 相同表求解统一字段不同内容的交集
  11. C# MVC 自学笔记—5 添加模型
  12. 关于table参数的一些问题
  13. oracle安装时,条件检查不通过解决办法
  14. 七牛云音频转码准备工作之如何创建音视频处理私有队列pipeline
  15. Codeforces Round #529 (Div. 3) C. Powers Of Two(数学????)
  16. [CTSC2017]吉夫特
  17. 解决centos6.5不能识别NTFS格式的移动硬盘或U盘问题
  18. Linux 环境下 网络IO模型
  19. 第七次Scrum冲刺
  20. Spark案例分析

热门文章

  1. 常用的ppt技巧
  2. postgresql批量插入copy_from()的使用
  3. 『GoLang』面向对象
  4. [转载]Samba 4实现windows匿名访问Linux共享!
  5. GIS应用|快速搭建REST地图服务
  6. PolarDB PostgreSQL DDL同步原理
  7. 简单Tab切换
  8. Firewalls文件配置防火墙
  9. Azure Devops实践(5)- 构建springboot项目打包docker镜像及容器化部署
  10. Miller Rabin 详解 &amp;&amp; 小清新数学题题解