热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

那些年我们排过的序之希尔排序

基本思想先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后

基本思想

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2

该方法实质上是一种分组插入方法引

比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比[1]较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。

一般的初次取序列的一半为增量,以后每次减半,直到增量为1。

排序过程

假设待排序文件有10个记录,其关键字分别是:

四九,三八,六五,九七,七六,一三,二七,四九,五五,零四。

增量序列的取值依次为:

五,三,一[2]

缩小增量

希尔排序属于插入类排序,是将整个无序列分割成若干小的子序列分别进行插入排序。

排序过程:先取一个正整数d1

[3] 三趟结果

零四 一三 二七 三八 四九 四九 五五 六五 七六 九七

Shell排序

Shell排序的算法实现:

1. 不设监视哨的算法描述

void ShellPass(SeqList R,int d)

{//希尔排序中的一趟排序,d为当前增量

for(i&#61;d&#43;1;i<&#61;n&#xff1b;i&#43;&#43;) //将R[d&#43;1&#xff0e;&#xff0e;n]分别插入各组当前的有序区

if(R[ i ].key

R[0]&#61;R[i];j&#61;i-d&#xff1b; //R[0]只是暂存单元&#xff0c;不是哨兵

do {//查找R的插入位置

R[j&#43;d]&#61;R[j]&#xff1b; //后移记录

j&#61;j-d&#xff1b; //查找前一记录

}while(j>0&&R[0].key

R[j&#43;d]&#61;R[0]&#xff1b; //插入R到正确的位置上

} //endif

优劣

不需要大量的辅助空间&#xff0c;和归并排序一样容易实现。希尔排序是基于插入排序的一种算法&#xff0c; 在此算法基础之上增加了一个新的特性&#xff0c;提高了效率。希尔排序的时间复杂度与增量序列的选取有关&#xff0c;例如希尔增量时间复杂度为O(n²)&#xff0c;而Hibbard增量的希尔排序的时间复杂度为O(N(3/2))&#xff0c;但是现今仍然没有人能找出希尔排序的精确下界。希尔排序没有快速排序算法快 O(N*(logN))&#xff0c;因此中等大小规模表现良好&#xff0c;对规模非常大的数据排序不是最优选择。但是比O(N^2)复杂度的算法快得多。并且希尔排序非常容易实现&#xff0c;算法代码短而简单。 此外&#xff0c;希尔算法在最坏的情况下和平均情况下执行效率相差不是很多&#xff0c;与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡&#xff0c;几乎任何排序工作在开始时都可以用希尔排序&#xff0c;若在实际使用中证明它不够快&#xff0c;再改成快速排序这样更高级的排序算法. 本质上讲&#xff0c;希尔排序算法的一种改进&#xff0c;减少了其复制的次数&#xff0c;速度要快很多。 原因是&#xff0c;当N值很大时数据项每一趟排序需要的个数很少&#xff0c;但数据项的距离很长。当N值减小时每一趟需要和动的数据增多&#xff0c;此时已经接近于它们排序后的最终位置。 正是这两种情况的结合才使希尔排序效率比插入排序高很多。

时间性能

1&#xff0e;增量序列的选择

Shell排序的执行时间依赖于增量序列。

好的增量序列的共同特征&#xff1a;

① 最后一个增量必须为1&#xff1b;

② 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。

有人通过大量的实验&#xff0c;给出了较好的结果&#xff1a;当n较大时&#xff0c;比较和移动的次数约在nl.25到1.6n1.25之间。

2&#xff0e;Shell排序的时间性能优于直接插入排序

希尔排序的时间性能优于直接插入排序的原因&#xff1a;

①当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。

②当n值较小时&#xff0c;n和n2的差别也较小&#xff0c;即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。

③在希尔排序开始时增量较大&#xff0c;分组较多&#xff0c;每组的记录数目少&#xff0c;故各组内直接插入较快&#xff0c;后来增量di逐渐缩小&#xff0c;分组数逐渐减少&#xff0c;而各组的记录数目逐渐增多&#xff0c;但由于已经按di-1作为距离排过序&#xff0c;使文件较接近于有序状态&#xff0c;所以新的一趟排序过程也较快。

因此&#xff0c;希尔排序在效率上较直接插入排序有较大的改进。

希尔排序是按照不同步长对元素进行插入排序&#xff0c;当刚开始元素很无序的时候&#xff0c;步长最大&#xff0c;所以插入排序的元素个数很少&#xff0c;速度很快&#xff1b;当元素基本有序了&#xff0c;步长很小&#xff0c;插入排序对于有序的序列效率很高。所以&#xff0c;希尔排序的时间复杂度会比o(n^2)好一些。由于多次插入排序&#xff0c;我们知道一次插入排序是稳定的&#xff0c;不会改变相同元素的相对顺序&#xff0c;但在不同的插入排序过程中&#xff0c;相同的元素可能在各自的插入排序中移动&#xff0c;最后其稳定性就会被打乱&#xff0c;所以shell排序是不稳定的。

举例阐述&#xff1a;

例如&#xff0c;假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ]&#xff0c;如果我们以步长为5开始进行排序&#xff0c;我们可以通过将这列表放在有5列的表中来更好地描述算法&#xff0c;这样他们就应该看起来是这样&#xff1a;

13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10

然后我们对每列进行排序&#xff1a;

10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45

将上述四行数字&#xff0c;依序接在一起时我们得到&#xff1a;[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].这时10已经移至正确位置了&#xff0c;然后再以3为步长进行排序&#xff1a;

10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45

排序之后变为&#xff1a;

10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94

最后以1步长进行排序&#xff08;此时就是简单的插入排序了&#xff09;。

图示&#xff1a;

C&#43;&#43;代码实现&#xff1a;

 

#include
 
void  shellsort(int *data, size_t size);

 

 int i, j, temp;
 int gap &#61; 0;

 

int main()
{
     const int n &#61; 5;

 

     int a[] &#61; {5, 4, 3, 2, 1};
  shellsort(a,5);
   /*  while (gap<&#61;n)
     {
          gap &#61; gap * 3 &#43; 1;
     }
     while (gap > 0)
     {
         for ( i &#61; gap; i          {
             j &#61; i - gap;
             temp &#61; a[i];            
             while (( j >&#61; 0 ) && ( a[j] > temp ))
             {
                 a[j &#43; gap] &#61; a[j];
                 j &#61; j - gap;
             }
             a[j &#43; gap] &#61; temp;
         }
         gap &#61; ( gap - 1 ) / 3;
     } */
  for(i&#61;0;i<5;i&#43;&#43;)
     printf("%d\n",a[i]);
 }

 


void shellsort(int *data, size_t size)
{

 

 int key;
  int j &#61; 0;
     for (gap &#61; size / 2; gap > 0; gap /&#61; 2)
         for ( i &#61; gap; i          {
 
              key &#61; data[i];
            
              for( j &#61; i -gap; j >&#61; 0 && data[j] > key; j -&#61;gap)
              {
                 data[j&#43;gap] &#61; data[j];
               } 
              data[j&#43;gap] &#61; key;
          }
 }


转载于:https://www.cnblogs.com/hedengfeng/p/3407974.html


推荐阅读
author-avatar
心梦飞扬-吕
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有