热门标签 | 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


推荐阅读
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • 本文探讨了如何在模运算下高效计算组合数C(n, m),并详细介绍了乘法逆元的应用。通过扩展欧几里得算法求解乘法逆元,从而实现除法取余的计算。 ... [详细]
  • PyCharm下载与安装指南
    本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • C++实现经典排序算法
    本文详细介绍了七种经典的排序算法及其性能分析。每种算法的平均、最坏和最好情况的时间复杂度、辅助空间需求以及稳定性都被列出,帮助读者全面了解这些排序方法的特点。 ... [详细]
  • 本文深入探讨 MyBatis 中动态 SQL 的使用方法,包括 if/where、trim 自定义字符串截取规则、choose 分支选择、封装查询和修改条件的 where/set 标签、批量处理的 foreach 标签以及内置参数和 bind 的用法。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • Splay Tree 区间操作优化
    本文详细介绍了使用Splay Tree进行区间操作的实现方法,包括插入、删除、修改、翻转和求和等操作。通过这些操作,可以高效地处理动态序列问题,并且代码实现具有一定的挑战性,有助于编程能力的提升。 ... [详细]
  • 使用Vultr云服务器和Namesilo域名搭建个人网站
    本文详细介绍了如何通过Vultr云服务器和Namesilo域名搭建一个功能齐全的个人网站,包括购买、配置服务器以及绑定域名的具体步骤。文章还提供了详细的命令行操作指南,帮助读者顺利完成建站过程。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • 文件描述符、文件句柄与打开文件之间的关联解析
    本文详细探讨了文件描述符、文件句柄和打开文件之间的关系,通过具体示例解释了它们在操作系统中的作用及其相互影响。 ... [详细]
  • 深入理解Java泛型:JDK 5的新特性
    本文详细介绍了Java泛型的概念及其在JDK 5中的应用,通过具体代码示例解释了泛型的引入、作用和优势。同时,探讨了泛型类、泛型方法和泛型接口的实现,并深入讲解了通配符的使用。 ... [详细]
  • 汇编语言等号伪指令解析:探究其陡峭的学习曲线
    汇编语言以其独特的特性和复杂的语法结构,一直被认为是编程领域中学习难度较高的语言之一。本文将探讨汇编语言中的等号伪指令及其对初学者带来的挑战,并结合社区反馈分析其学习曲线。 ... [详细]
  • 本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ... [详细]
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社区 版权所有