设为首页 加入收藏

TOP

经典(Java版)排序算法的分析及实现之二希尔排序(一)
2015-02-02 14:36:23 来源: 作者: 【 】 浏览:18
Tags:经典 Java 排序 算法 分析 实现 之二 希尔

插入排序—希尔排序


希尔排序是1959 年由D.L.Shell 提出来的,相对直接插入排序有较大的改进。希尔排序的实质就是分组插入排序,该方法又称缩小增量排序。


基本算法:


先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。


算法最开始以一定的步长进行排序,然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。Donald Shell 最初建议步长选择为\frac{n}{2}并且对步长取半直到步长达到 1。虽然这样取可以比\mathcal{O}(n^2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。


希尔排序示例:n=10的一个数组 58 27 32 93 65 87 58 46 9 65,步长为n/2。


第一次排序 步长为 10/2 = 5


? ?58? 27? 32? 93? 65? 87? 58? 46? 9? 65
? ? 1A? ? ? ? ? ? ? ? ? 1B
? ? ? ? 2A? ? ? ? ? ? ? ? ? ? 2B
? ? ? ? ? ? 3A? ? ? ? ? ? ? ? ? ? 3B
? ? ? ? ? ? ? ? ? 4A? ? ? ? ? ? ? ? ? ? 4B
? ? ? ? ? ? ? ? ? ? ? 5A? ? ? ? ? ? ? ? ? 5B


? ??首先将待排序元素序列分组,以5为步长,(1A,1B),(2A,2B),(3A,3B)等为分组标记,大写字母表示是该组的第几个元素,数字相同的表示在同一组,这样就分成5组,即(58,87),(27,58),(32,46),(93,9),(65,65),然后分别对各分组进行直接插入排序,排序后5组为(58,87),(27,58),(32,46),(9,93),(65,65),分组排序只是变得各个分组内的下表,下同。


? ? 第二次排序 步长为 5/2 = 2


? ? 58? 27? 32? 9? 65? 87? 58? 46? 93? 65


? ? 1A? ? ? 1B? ? ? 1C? ? ? 1D? ? ? 1E


? ? ? ? 2A? ? ? 2B? ? ? 2C? ? ? 2D? ? ? ? 2E


? ? 第三次排序 步长为 2/2 = 1


? ? 32? 9? 58? 27? 58? 46? 65? 65? 93? 87


? 1A? 1B? 1C? 1D? 1E? 1F? 1G? 1H? 1I? 1J


? ? 第四次排序 步长为 1/2 = 0 得到有序元素序列


? ? 9? 27? 32? 46? 58? 58? 65? 65? 87? 93


? ? 按照希尔排序算法定义


/**
? ? * 按照希尔排序定义实现
? ? *
? ? * @param sortList
? ? */
? ? static void shellSort1(Integer[] sortList) {
? ? ? ? int i, j, step;
? ? ? ? int len = sortList.length;
? ? ? ? // 步长除以2
? ? ? ? for (step = len / 2; step > 0; step /= 2)
? ? ? ? ? ? /**
? ? ? ? ? ? *? 分别对每个分组进行直接插入排序
? ? ? ? ? ? */
? ? ? ? ? ? for (i = 0; i < step; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? for (j = i + step; j < len; j += step)
? ? ? ? ? ? ? ? ? ? if (sortList[j] < sortList[j - step]) {
? ? ? ? ? ? ? ? ? ? ? ? int temp = sortList[j];
? ? ? ? ? ? ? ? ? ? ? ? int k = j - step;
? ? ? ? ? ? ? ? ? ? ? ? while (k >= 0 && sortList[k] > temp) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? sortList[k + step] = sortList[k];
? ? ? ? ? ? ? ? ? ? ? ? ? ? k -= step;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? sortList[k + step] = temp;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? }


对上面的代码进行优化,按照从从第一个步长数据开始,依次对每个元素与自己组内的数据进行直接插入排序


? /**
? ? * 从第一个步长数据开始,依次对每个元素与自己组内的数据进行直接插入排序
? ? * @param sortList
? ? */
? ? static void shellSort2(Integer[] sortList) {
? ? ? ? int j, step;
? ? ? ? int len = sortList.length;
? ? ? ? for (step = len / 2; step > 0; step /= 2)
? ? ? ? ? ? for (j = step; j < len; j++)
? ? ? ? ? ? ? ? /**
? ? ? ? ? ? ? ? * 从数组第step个元素开始,然后将每个元素与自己组内的数据进行直接插入排序
? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? if (sortList[j] < sortList[j - step]) {
? ? ? ? ? ? ? ? ? ? int temp = sortList[j];
? ? ? ? ? ? ? ? ? ? int k = j - step;
? ? ? ? ? ? ? ? ? ? while (k >= 0 && sortList[k] > temp) {
? ? ? ? ? ? ? ? ? ? ? ? sortList[k + step] = sortList[k];
? ? ? ? ? ? ? ? ? ? ? ? k -= step;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? sortList[k + step] = temp;
? ? ? ? ? ? ? ? }
? ? }


算法复杂度


1、时间复杂度


希尔排序耗时的操作有:比较 + 后移赋值。时间复杂度如下:


1) 最好情况:序列是升序排列,在这种情况下,需要进行的比较操作需(n-1)次。后移赋值操作为0次。即O(n)


2) 最坏情况:O(nlog2n)。


3) 渐进时间复杂度(平均时间复杂度):O(nlog2n)


平均时间复杂度:O(nlog2n),希尔排序在最坏的情况下和平均情况下执行效率相差不是很多, 与此同时快速排序(O(log2n))在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法。


增量序列的选择


Shell排序的执行时间依赖于增量序列。


1) 最后一个增量必须为1;


2) 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。


Shell排序的时间性能优于直接插入排序


1)当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。


2)当n值较小时,n和的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0()差别不大。


3)在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。


2、空间复杂度:O(1)


希尔排序是在原输入数组上进行后移赋值操作的(称“就地排序”),所需开辟的辅助空间跟输入数组规模无关,所以空间复杂度为:O(1)


稳定性


由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。


附件希尔排序下载


------------------------------------------分割线------------------------------------------


具体下载目录在 /2014年资料/12月/

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇为什么Go语言不是想象中的那么好 下一篇经典(Java版)排序算法的分析及..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: