排序的方法有很多,一般言,很难说哪一种方法是最好的。每一种方法都有优缺点,有各自应用的环境。排序一般会进行两种操作1、比较两关键字大小;2、将记录从一个位置移到另一个位置;前者通常来说是必要的,而后者则可以通过改变记录存储方式来避免。后面还会用一篇专门的文章来讨论一下怎么来分析这些算法的复杂度。还请您留意,应该就是最近一周出来!(2015.6.20前)
常见的内部排序算法大致可以分为以下六类共十种:
选择排序:(1)直接选择排序;(2)堆排序;
交换排序:(3)冒泡排序;(4)快速排序;
插入排序: (5)直接插入 排序; (6)折半插入排序;(7)Shell排序;
(8)归并排序;
(9)筒式排序;
(10)基数排序;
下面就将用十篇文章分别归纳这十种排序,这一篇是Shell排序:
有些书中,除了考虑排序外还分析了排序的稳定性,简单说就是,两个相等的元素在排序前后相对位置是否变化。比如排序前[2*, 9 , 4, 2, 7], 排序后[2, 2*, 4, 7 ,9],就不是稳定排序,我们也借用这种思路,在源程序中加入了一个数据封装类DataWrap。Shell排序可以看成是直接排序算法的改进版本。试想一个场景:当直接排序进行到第 i 个元素时( i 很到),若data[i]应该排在开始处附近,此时的比较和移动数据位就很多,效率很低。Shell排序的改进在于,增大了数据每次移动的间隔(后面有公式说明,不绝对),在这些有间隔的元素里插入元素,能使得数据大跨度移动。然后在减小这个跨度直至为一。排序项之间的间隔称为增量,用字母 h 表示。比较常用的 h 公式由Knuth提出: h = 3 * h + 1 和 h = (h - 1) / 3;增量一般取值就是:1, 4, 13, 40 ......
源代码如下(难理解的地方均已详细注释):
//a example to SelectSort
//blog.youkuaiyun.com/code_7
//HanChun at XiDian University
//input:7 2 0 8 4 2*
package c20150615;
import java.util.Arrays;
//定义了一个数据包装类,用来在体现排序算法稳定性的时候更容易理解!
class DataWrap implements Comparable<DataWrap> {
int data;
String flag;
public DataWrap(int data, String flag){
this.data = data;
this.flag = flag;
}
public String toString(){
return data + flag;
}
public int compareTo(DataWrap dw){
return this.data > dw.data ? 1 : (this.data == dw.data ? 0 : -1);
}
}
public class ShellSort {
public static DataWrap[] shellSort(DataWrap[] data){
int arrayLength = data.length;
int h = 1;
while(h <= arrayLength){
h = h * 3 - 1; //计算出初始跨度, blog.youkuaiyun.com/code_7 文中有说明
}
/*
* Shell排序的难点就在于这个While的理解:
* 首先保存当前待排序数tem,然后用这个数和前
* 一个跨度的数据比较,如果小于这个数则进入if(){}
* if里面的操作跟其他排序舒服有些许不一样,它并
* 没有直接去交换,而是直接去比较相邻间隔的两个数,
* 就是这里的内层for(){}做的事情,后面小于前面
* 就把前面元素往后移动h间隔。最后再插入tem到合适位置。
*/
while(h > 0){
for(int i = h; i < arrayLength; i++){
DataWrap tem = data[i]; //保存待排序数
if(data[i].compareTo(data[i - h]) < 0){
int j = i - h;
for(; j >= 0 && data[j].compareTo(tem) > 0; j -= h){
data[j+h] = data[j];
}
data[j + h] = tem;
}
}
h = (h - 1) / 3; //缩小跨度,blog.youkuaiyun.com/code_7 文中有说明
}
return data;
}
public static void main(String[] args) {
DataWrap[] data ={new DataWrap(7,""),new DataWrap(2,""),new DataWrap(0,""),
new DataWrap(8,""),new DataWrap(4,""),new DataWrap(2,"*")};
System.out.println("排序之前的元素为:" + Arrays.toString(data));
System.out.println("排序之后的元素为: " + Arrays.toString(shellSort(data)));
}
}
结果为:
排序之前的元素为:[7, 2, 0, 8, 4, 2*]
排序之后的元素为: [0, 2, 2*, 4, 7, 8]
对您有启发吗?欢迎拍砖!