RSS
热门关键字:  java  Ajax  JSP  JSF  Struts
当前位置 : 首页>Java>列表

shell排序

来源: 作者: 时间:2007-08-11 点击:
希尔排序(Shell Sort)是插入排序的一种。因D.L.Shell于1959年提出而得名。

java代码如下:
public class shellSort {
/**
* 主调函数
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//数组长度
int lenArgs = args.length;
String[] sortArray = new String[lenArgs];
sortArray = sortDoing(args, lenArgs);
//循环显示
for(int i=0; i < lenArgs; i++){
System.out.print(sortArray[i] + " ");
}
}
/**
* 进行排序
* @param args
* @param lenArgs
*/
private static String[] sortDoing(String[] args, int lenArgs) {
// TODO Auto-generated method stub
// 增量从数组长度的一半开始,每次减小一倍
for (int increment = lenArgs / 2; increment > 0; increment /= 2)
//从i等于折半长度开始,依次递增
for (int i = increment; i < lenArgs; i++){
//把i之前大于array[i]的数据向后移动
for (int j = i - increment; j >= 0; j -= increment){
int temp = Integer.parseInt(args[j]);
if (temp > Integer.parseInt(args[j + increment])){
//对比较后的数据进行交换位置
args[j] = args[j + increment];
args[j + increment] = String.valueOf(temp);
}
}
}
return args;
}
}

希尔排序基本思想

基本思想:
  先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插人排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
 该方法实质上是一种分组插入方法。

给定实例的shell排序的排序过程

 假设待排序文件有10个记录,其关键字分别是:
49,38,65,97,76,13,27,49,55,04。
 增量序列的取值依次为:
5,3,1
 排序过程如【动画模拟演示】。

Shell排序的算法实现

1. 不设监视哨的算法描述
void ShellPass(SeqList R,int d)
{//希尔排序中的一趟排序,d为当前增量
for(i=d+1; i<=n;i++) //将R[d+1..n]分别插入各组当前的有序区
if(R[i].key<R[i-d].key){
R[0]=R[i]; j=i-d; //R[0]只是暂存单元,不是哨兵
do {//查找R[i]的插入位置
R[j+d];=R[j]; //后移记录
j=j-d; //查找前一记录
}while(j>0&&R[0].key<R[j].key);
R[j+d]=R[0]; //插入R[i]到正确的位置上
} //endif
} //ShellPass

void ShellSort(SeqList R)
{
int increment=n; //增量初值,不妨设n>0
do {
increment=increment/3+1; //求下一增量
ShellPass(R,increment); //一趟增量为increment的Shell插入排序
}while(increment>1)
} //ShellSort
注意:
  当增量d=1时,ShellPass和InsertSort基本一致,只是由于没有哨兵而在内循环中增加了一个循环判定条件"j>0",以防下标越界。

2.设监视哨的shell排序算法
 具体算法【参考书目[12] 】

算法分析

1.增量序列的选择
 Shell排序的执行时间依赖于增量序列。
 好的增量序列的共同特征:
  ① 最后一个增量必须为1;
  ② 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。
 有人通过大量的实验,给出了目前较好的结果:当n较大时,比较和移动的次数约在nl.25到1.6n1.25之间。

2.Shell排序的时间性能优于直接插入排序
 希尔排序的时间性能优于直接插入排序的原因:
  ①当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。
  ②当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。
  ③在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。
 因此,希尔排序在效率上较直接插人排序有较大的改进。

3.稳定性
 希尔排序是不稳定的。参见上述实例,该例中两个相同关键字49在排序前后的相对次序发生了变化。


shell排序是对插入排序的一个改装,它每次排序把序列的元素按照某个增量分成几个子序列,对这几个子序列进行插入排序,然后不断的缩小增量扩大每个子序列的元素数量,直到增量为一的时候子序列就和原先的待排列序列一样了,此时只需要做少量的比较和移动就可以完成对序列的排序了.


// shell排序
void ShellSort(int array[], int length)
{
int temp;

// 增量从数组长度的一半开始,每次减小一倍
for (int increment = length / 2; increment > 0; increment /= 2)
for (int i = increment; i < length; ++i)
{
temp = array[i];
// 对一组增量为increment的元素进行插入排序
for (int j = i; j >= increment; j -= increment)
{
// 把i之前大于array[i]的数据向后移动
if (temp < array[j - increment])
{
array[j] = array[j - increment];
}
else
{
break;
}
}
// 在合适位置安放当前元素
array[j] = temp;
}
}

另附写法:
目前应用最多的应该是快速排序法,但是shell运算法作为一个经典的算法,还是有必要了解一下的。tcpl的p51将shell排序法作为一个例子简单得描述了一下。

/*按递增顺序对v[0]-v[n-1]排序*/

void shellsort(int v[], int n)

{ int gap,i,j,temp;

for(gap = n/2; gap > 0; gap /= 2)

for(i = gap; i < n; i++)

for(j = i - gap; j >= 0 && v[j] > v [j + gap]; j -= gap)

temp = v[j], v[j] = v[ j + gap], v[j + gap] = temp;

}

Shell排序法是D.L.Shell于1959年发明的,它运用一种模糊排序的思想,将一个数字序列分成n/2数字序列,一次循环使每一个序列排好顺序,然后再变为n/4个序列,再次排序……随着序列减少最后变为一个,也就完成了排序。值得一提的巧妙之处在于,由于前面的排序的缘故,正在排序的数列只需一个循环就可以完成排序。Shell排序法解决了临位交换的那些排序法在数列过长及过于杂乱的情况下的效率过低问题。效率的计算我还没有学会,所以不能加以分析。

最新评论共有 0 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册
Google Adsense
相关文章