排序算法系列:Shell 排序算法
来源:互联网 发布:淘宝查询买家退货率 编辑:程序博客网 时间:2024/06/04 01:15
概述
希尔排序(Shell Sort)是 D.L.Shell 于 1959 年提出来的一种排序算法,在这之前排序算法的时间复杂度基本都是 O(
版权说明
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
本文作者:Coding-Naga
发表日期: 2016年4月12日
本文链接:http://blog.csdn.net/lemon_tree12138/article/details/51127533
来源:CSDN
更多内容:分类 >> 算法与数学
目录
- 概述
- 版权说明
- 目录
- 算法简介
- 算法原理分析
- 算法步骤
- 逻辑实现
- 复杂度分析
- 问题解答
- Ref
- Github源码下载
算法简介
希尔排序(Shell Sort)是 D.L.Shell 于 1959 年提出来的一种排序算法,在这之前排序算法的时间复杂度基本都是 O(
n2 ) 的,希尔排序算法是突破这个时间复杂度的第一批算法之一。
– 《大话数据结构》
算法原理分析
在上一篇《排序算法系列:插入排序算法》一文中,我们说到了一种复杂度为 O(
基于上面基本有序和小数据量的提示,这里就有了希尔排序的实现。希尔所做的就是分组,在每个分组中进行插入排序。如下就是希尔排序中分组的示意图:

在上图中,我们将一个长度为 10 的序列,分组成 3 组。除最后一组以外的分组都包含了 4 个元素。可是,我们排序的时候并不是在这些分组内部进行的。而是我们要按照上面圆形的标号来进行插入排序,也就是排序中的 [4, 9, 7]。你可以先想一想这是为什么,在文章的最后,我再说明这个问题。
上面从详细地说明了希尔排序的由来及希尔排序的分组精髓。那么现在就要说希尔排序中的插入排序,是的没有错。毕竟希尔排序的核心就是分组+插入排序嘛。在这个示意图中,我们可以很明显地看出它想表达的东西。这里只是将[3, 9, 7]看成了一个整体,对于其它的元素,暂时与[3, 9, 7]无关。
通过上面的两步操作,我们可以得到一个序列 T1 = [4, 0, 6, 1, 7, 2, 8, 5, 9, 3]。咦,这个序列还是无序的呀,怎么回事?我们说希尔排序的核心是分组和获得一个基本有序的数组。这里说的是基本有序,并未做出承诺说这个序列已经有序。那么,现在要做的就是继续分组+插入排序。当然,对应的 step 是要进行修改的。详细过程,参见下面的算法步骤。
算法步骤
通过上面的算法原理分析,这里可以总结出算法实现的步骤。如下:
1. 获得一个无序的序列 T0 = [4, 3, 6, 5, 9, 0, 8, 1, 7, 2],并计算出当前序列状态下的步长 step = length / 3 + 1;
2. 对序列 T0 按照步长周期分组;
3. 对每个子序列进行插入排序操作;
4. 判断此时的步长 step 是否大于 1?如果比 1 小或是等于 1,停止分组和对子序列的插入排序,否则,就继续;
5. 修改此时的步长 step = step / 3 + 1,并继续第 2 到第 4 步;
6. 排序算法结束,序列已是一个整体有序的序列。
逻辑实现
这是Shell 排序的核心模块,也是分组的关键步骤
private void core(int[] array) { int arrayLength = array.length; int step = arrayLength; do { step = step / 3 + 1; for (int i = 0; i < step; i++) { insert(array, i, step); } System.err.println(Arrays.toString(array)); } while (step > 1); }
希尔排序的直接插入排序,注意这里不同的是它只是针对某一个分组子序列进行插入排序
private void insert(int[] array, int offset, int step) { int arrayLength = array.length; int groupCount = arrayLength / step + (arrayLength % step > offset ? 1 : 0); for (int i = 1; i < groupCount; i++) { int nextIndex = offset + step * i; int waitInsert = array[nextIndex]; while(nextIndex - step >= 0 && waitInsert < array[nextIndex - step]) { array[nextIndex] = array[nextIndex - step]; nextIndex -= step; } array[nextIndex] = waitInsert; } }
更多详细逻辑实现,请参见文章结尾的源码链接。
复杂度分析
问题解答
- 为什么我们排序的时候并不是在这些分组内部进行的?
答:这里我们分组的目的在于要完成的是对整个序列的基本序列处理,那么我们肯定想要让这些分组的数据尽量地分散开。如果要针对每个分组内部进行插入排序,那么之后的每次操作,都会是在内部进行的,这样的结果就是每个分组内部已经有序,只是整体仍然是无序的。 - 分组步长的计算公式为什么是 step = step / 3 + 1?
答:这里的步长计算很关键,可是究竟应该选取什么样的增量才是最好的,目前还尚未解决。不过大量的研究表明,当增量序列为 dlta[k] =2t−k+1 - 1 (0 <= k <= t <= [log2 (n+1)])时,可以获得不错的效果,其时间复杂度为 O(n3/2 )。
Ref
- 《大话数据结构》
Github源码下载
https://github.com/William-Hai/ArraySortAlgorithm/blob/master/src/org/algorithm/array/sort/impl/ShellSort.java
- 排序算法系列:Shell 排序算法
- 排序算法---Shell排序
- 排序算法--shell排序
- 排序算法--Shell排序
- 排序算法系列七(希尔排序也称shell排序)
- 大话排序算法-shell排序
- 排序算法之shell排序
- 八大排序算法-shell 排序
- 排序算法之shell排序
- 排序算法(四)-Shell排序
- Shell排序算法
- 排序算法-Shell sort
- Shell排序算法
- SHELL排序算法
- 算法复习--shell排序
- shell排序算法
- 希尔(shell)排序算法
- 算法-->shell排序
- mysql用户权限相关
- java中HashSet和LinkedHashSet
- mysql修改root密码
- C语言模拟php basename() 函数
- 三种定时器的使用
- 排序算法系列:Shell 排序算法
- SQLServer 2008自动备份数据库
- [温故而知新] 《深度探索c++对象模型》——运行期语意
- SQLServer数据库备份(语句方式)
- Python - cannot import OpenCV module?
- 【珍藏】高性能IO模型浅析
- linux 硬盘挂载 fdisk parted命令
- sqlserver2008新增只有查询查询权限的账号
- SQL Server日志文件过大的处理