数据结构与算法之六(希尔排序,非稳定排序)
2017-10-30 17:12
537 查看
旁白:这一节的内容消化起来没这么容易,那个pdf说的也比较复杂,建议大家在网上搜资料去看原理还容易一点。
还记得前面说的三种基本排序吗?插入排序可以说是性能较高的一种,但是如果完全逆序的插入排序,复制和移动效率依然低下。在此基础上有人提出了希尔排序,基于n-增量排序对插入排序进行优化。所谓n增量就是从原序列中选出间隔n的序列
2.原理
对于序列序列9,8,7,6,5,4,3,2,1。
用插入排序依次插入,需要的移动次数是1+2+3+…+8=36。
1) 如果我们采用4-增量排序,上述序列会被分解成几个子序列
2)分别对序列1234进行插入排序,因为间隔了n,每次移动n隔,减少了移动次数
此时4-增量排序结束,需要减小增量,进行更细粒度的排序
3)Knuth提出增量排序最佳间隔1,4,13,40,…公式d(x+1)=3*d(x)+1,所以接下来采用d(x)=(4-1)/3=1,1-增量排序
至此1增量排序结束,可以看出整个希尔排序的结束条件就是1增量排序结束。同时,移动次数确实有效减少。
3.归纳:
实现希尔排序必须实现的几个点:
1)增量选择及控制减小
2)对n-增量序列进行插入排序
3)结束条件:1-增量结束
4.java实现
书中的增量递减选的是d(x-1)=d(x)/2,据说是希尔排序的发明者提出的,可是后来证明这种并不是最佳方案,而是刚才说到的d(x+1)=3*d(x)+1。所以我的实现是基于这种增量变化的。
旁白:其实对算法又过了解的童鞋会比较清楚诸如hash算法之类的因子都会选用质数,可以让算法更优。另外,最里面的那段插入排序不要看我写的代码去理解,可能看的比较迷糊。而是自己动手写一个n-增量的插入排序,就能知道我为什么这么写了。
2017.10.31补充:
5.希尔排序的复杂度。
由于希尔排序增量的不确定性,你可以是我们刚才用的1,4,13,…这样选择增量,也可以是1,2,4,8,…或者干脆就是1,2,3,4,…也就是一千个人可以写出一千种希尔排序。其复杂度是无法估量的,为O(n^m),其中
6.希尔排序的稳定性。
在希尔排序的学习中头一次接触到排序的稳定性一说,百科了一个下,一个排序算法是否稳定是这样定义的:
简单讲,相同元素位序不变就是稳定,很明显希尔排序是不稳定的。比如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
希尔排序
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
最后留一个问题:为什么要讨论排序的稳定性?
相关文章推荐
- C语言学习历程(十七)数据结构与排序(冒泡、选择、希尔排序)算法
- 算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)
- 【数据结构与算法】内部排序之一:插入排序和希尔排序的N中实现(不断优化,附完整源码)
- 【数据结构与算法】内部排序之一:插入排序和希尔排序的N中实现(不断优化,附完整源码)
- 数据结构与算法——插入类排序(直接插入排序,希尔排序)
- 【数据结构与算法】【排序】希尔排序的代码实现
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
- SDUT 数据结构实验之排序六:希尔排序
- Java-数据结构与算法-选择排序与冒泡排序
- 数据结构与算法——冒泡排序、选择排序和快速排序
- 数据结构与算法 -排序
- 数据结构实验之排序六:希尔排序
- 【数据结构与算法】排序
- 数据结构实验之排序六:希尔排序
- 【数据结构与算法】选择排序
- 【数据结构与算法】内部排序之五:计数排序、基数排序和桶排序(含完整源码)
- 基础数据结构算法_计数排序,基数排序,桶排序
- 数据结构与算法——直接插入排序
- 基础算法(二)---数据结构之排序
- 数据结构实验之排序六:希尔排序