八大排序之希尔排序
一、基本思想
希尔排序是在插入排序的基础上进行改进的一种基于渐进思想的高效排序算法。它将一个序列从第一个元素开始,按增量d将序列划分成若干个子序列。
(例如:1 , 1+d ,1+2d..为一组,2 , 2+d , 2+2d...为一组) 对每个子序列进行插入排序,缩小增量d,这样,整个序列会渐渐的趋于有序;最后,当d=1时,整个序列排序完毕。排序过程的和插入排序十分相似,只不过希尔排序进行的是跳跃式的插入排序,相比于挨个比较的简单插入排序,它可以更有利于元素的移动,从而提高的排序效率。
二、实现方法
希尔排序的重点在于如何分组,如何对分组后的序列进行插入排序
1.数组a[]做待排序列,a[0]做暂存空间,不参与排序
2. 从每一组的第二个元素开始进行插入排序,注意进行一趟插入排序时,元素之间的距离不再是1,而是d
3.缩小增量,直到增量为1
三、实现代码
测试所用到的工具类 点击查看工具类
希尔排序代码实现的逻辑和插入排序十分相似,觉得代码难以看懂的话可以先熟练插入排序 点击查看插入排序
package sort; import sort.util.*; public class ShellSort implements ISort{ private void shellSort(int[] a , int d) { /* 这里为什么是从1+d开始,因为1 ~ d这几个分别在各自的组里位于第一个, 而插入排序默认第一个数在有序序列中, 只需对后面的元素进行插入排序 */ for(int i = 1+d; i < a.length; i++){ //a[0]做暂存空间,不作为数组中的元素参与排序 a[0] = a[i]; int j; for(j = i - d; j >= 1 && a[0] < a[j]; j -= d){ a[j+d] = a[j]; //j >= 1 的越界判断必须放在前面 } a[j+d] = a[0]; } } public void sort(int[] a) { int[] d = {9,5,2,1}; //增量序列 for(int i = 0; i < d.length; i++) { shellSort(a , d[i]); } } public static void main(String[] args) { int [] array = RandomArrayGenerator.getRandomArray(100 , 30); SortTestHelper.test(new ShellSort() , array); } }
测试结果:(查看结果时,忽略a[0],它不在待排记录)
四、算法分析
关于增量序列:到目前为止还没有绝对的最佳序列,一般选择有{...9 , 5 , 3 , 1},{...40 , 13 , 4 , 1}详见《数据结构与算法》。注意,增量序列中的值应当没有除1以外的公因子,且最后的增量必须为1.
时间复杂度:希尔排序的复杂度与增量序列有关,这涉及数学上一些未解决的难题。但肯定是在O(n) ~ O(n2)之间。
空间复杂度:O(1)
稳定性:不稳定.跳跃式交换位置,很可能改变相等元素的相对位置
希尔排序在插入排序的基础上有较大改进,它的设计思想十分符合人类的生活哲学,当一个问题一步解决十分困难时,我们可以分步解决,一步一步,渐渐的接近想要的答案!
本文个人编写,水平有限,如有错误,恳请指出,欢迎讨论分享。