您的位置:首页 > 理论基础 > 数据结构算法

数据结构与算法之六(希尔排序,非稳定排序)

2017-10-30 17:12 537 查看
旁白:这一节的内容消化起来没这么容易,那个pdf说的也比较复杂,建议大家在网上搜资料去看原理还容易一点。

希尔排序

1.介绍

还记得前面说的三种基本排序吗?插入排序可以说是性能较高的一种,但是如果完全逆序的插入排序,复制和移动效率依然低下。在此基础上有人提出了希尔排序,基于n-增量排序对插入排序进行优化。所谓n增量就是从原序列中选出间隔n的序列

2.原理

对于序列序列9,8,7,6,5,4,3,2,1。

用插入排序依次插入,需要的移动次数是1+2+3+…+8=36。

1) 如果我们采用4-增量排序,上述序列会被分解成几个子序列

原序列:9,8,7,6,5,4,3,2,1
序列1:  9          5         1
序列2:    8          4
序列3:       7          3
序列4:         6          2


2)分别对序列1234进行插入排序,因为间隔了n,每次移动n隔,减少了移动次数

//第一趟排序:4-增量排序
序列1:  1          5         9
序列2:     4         8
序列3:       3          7
序列4:         2          6
排序结果:1,4,3,2,5,8,7,6,9


此时4-增量排序结束,需要减小增量,进行更细粒度的排序

3)Knuth提出增量排序最佳间隔1,4,13,40,…公式d(x+1)=3*d(x)+1,所以接下来采用d(x)=(4-1)/3=1,1-增量排序

4-增量排序结果:1,4,3,2,5,8,7,6,9
序列1: 1   3   5   7   9
序列2:   4   2   8   6

//第二趟排序:1-增量排序
序列1: 1   3   5   7   9
序列2:   2   4   6   8
排序结果:1,2,3,4,5,6,7,8,9


至此1增量排序结束,可以看出整个希尔排序的结束条件就是1增量排序结束。同时,移动次数确实有效减少。

3.归纳:

实现希尔排序必须实现的几个点:

1)增量选择及控制减小

2)对n-增量序列进行插入排序

3)结束条件:1-增量结束

4.java实现

书中的增量递减选的是d(x-1)=d(x)/2,据说是希尔排序的发明者提出的,可是后来证明这种并不是最佳方案,而是刚才说到的d(x+1)=3*d(x)+1。所以我的实现是基于这种增量变化的。

/**
* 希尔排序 增量d=3*x+1
* @param array
*/
public static void sortArray(int[] array){

//选择合适的增量
int d=1;
while(d<intArray.length){
d=3*d+1;
}

int n = 1;
System.out.println("序列:"+Arrays.toString(intArray));
while(d>1){
//增量减小
d = (d-1)/3;
System.out.println("增量:d ="+d);

//排序
for(int i=0;i<d;i++){
//局部插入排序:i是第一位,i+d,i+2d,...依次插入
for(int j=i+d;j<intArray.length;j+=d){
int temp = intArray[j];
int k=j-d;
for(;k>=0;k-=d){
if(intArray[k]>temp){  //往后移动一位
intArray[k+d]=intArray[k];
}else{  //插入中止
break;
}
}
intArray[k+d]=temp;
}
}
System.out.println("第"+(n++)+"趟排序:"+Arrays.toString(intArray));
}
}


旁白:其实对算法又过了解的童鞋会比较清楚诸如hash算法之类的因子都会选用质数,可以让算法更优。另外,最里面的那段插入排序不要看我写的代码去理解,可能看的比较迷糊。而是自己动手写一个n-增量的插入排序,就能知道我为什么这么写了。

2017.10.31补充:

5.希尔排序的复杂度。

由于希尔排序增量的不确定性,你可以是我们刚才用的1,4,13,…这样选择增量,也可以是1,2,4,8,…或者干脆就是1,2,3,4,…也就是一千个人可以写出一千种希尔排序。其复杂度是无法估量的,为O(n^m),其中
(1<m<2)


6.希尔排序的稳定性。

在希尔排序的学习中头一次接触到排序的稳定性一说,百科了一个下,一个排序算法是否稳定是这样定义的:

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。


简单讲,相同元素位序不变就是稳定,很明显希尔排序是不稳定的。比如a[4]={4,3,3,1}。我们标记一下{4 , 3(1) , 3(2) , 1},进行2-增量排序的时候,结果为{3(2) , 1 , 4 , 3(1)}。3(2)跑到了3(1)前面,相对位置发生了变化。

各种排序稳定性,可以参考这里:

http://www.cnblogs.com/codingmylife/archive/2012/10/21/2732980.html

最后留一个问题:为什么要讨论排序的稳定性?

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: