shell排序

shell排序

    希尔排序(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的整数d 1作为第一个增量,把文件的全部记录分成d 1个组。所有距离为d l的倍数的记录放在同一个组中。先在各组内进行直接插人排序;然后,取第二个增量d 2<d 1重复上述的分组和排序,直至所取的增量d t=1(d t<d t-l<…<d 2<d 1),即所有记录放在同一组中进行直接插入排序为止。
     该方法实质上是一种分组插入方法。

给定实例的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较大时,比较和移动的次数约在n l.25到1.6n 1.25之间。

2.Shell排序的时间性能优于直接插入排序
     希尔排序的时间性能优于直接插入排序的原因:
  ①当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。
  ②当n值较小时,n和n 2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n 2)差别不大。
  ③在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量d i逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按d i-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排序法解决了临位交换的那些排序法在数列过长及过于杂乱的情况下的效率过低问题。效率的计算我还没有学会,所以不能加以分析。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值