排序算法三:Shell插入排序


声明:引用请注明出处http://blog.csdn.net/lg1259156776/


引言

在我的博文《“主宰世界”的10种算法短评》中给出的首个算法就是高效的排序算法。本文将对排序算法做一个全面的梳理,从最简单的“冒泡”到高效的堆排序等。

上一篇博文《排序算法二:二分(折半)插入排序》讲述了直接插入排序,本文讲述第三种插入排序算法:Shell插入排序。实际上它是改进自插入排序和冒泡排序。


排序相关的的基本概念

  • 排序:将一组杂乱无章的数据按一定的规律顺次排列起来。

    • 数据表( data list): 它是待排序数据对象的有限集合。
    • 排序码(key):通常数据对象有多个属性域,即多个数据成员组成,其中有一个属性域可用来区分对象,作为排序依据。该域即为排序码。每个数据表用哪个属性域作为排序码,要视具体的应用需要而定。
  • 分类
    • 内排序:指在排序期间数据对象全部存放在内存的排序;
    • 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。

排序算法的分析

排序算法的稳定性

如果在对象序列中有两个对象r[i]和r[j] ,它们的排序码k[i]==k[j] 。如果排序前后,对象r[i]和r[j] 的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。

排序算法的评价

时间开销

  • 排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。
  • 算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算

空间开销

算法执行时所需的附加存储。


Shell插入排序

基本思想

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插人排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt−l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。实际上当dt=1时,完全就是直接插入排序。但是经过多个分组的直接插入排序,最后一次完整的插入排序前数据表几乎已经是排好序了,因此shell sort充分利用了直接插入排序在数据表几乎已经有序的条件下工作高效的特点。

算法的C plus plus实现

根据算法的基本思想,shell插入排序的实现还是比较容易的,其C++实现如下:

#include <iostream>
#include <iomanip>
using namespace std; void print(int ar[], int sz, int step)
{
for(int i = 0; i < sz; ++i) {
if(((i + 1) % step) != 0)
cout << setw(3) << ar[i];
else
cout << setw(3) << ar[i] << endl; }
cout << endl;
} void ShellSort(int a[], int sz)
{
int i, j;
int step, temp;
step = sz / 2 ;
while(step) {
print(a, sz, step);
cout << "==>" << endl;
for (i = step; i < sz; i++) {
temp = a[i];
j = i;
while (j >= step && a[j - step] > temp) {
a[j] = a[j - step];
j = j - step;
}
a[j] = temp;
}
print(a, sz, step);
cout << "current array" << endl;
print(a, sz, sz);
cout << "----------------" << endl; step = step / 2.2;
}
} int main(void)
{
int a[] = {13, 14, 94, 33, 82, 25, 59, 94, 65, 23, 45, 27, 73, 25, 39, 10};
const size_t sz = sizeof(a)/sizeof(a[0]); cout << "Initial array" << endl;
print(a,sz,sz);
cout << "-------------" << endl; ShellSort(a,sz); cout << "Sorted array" << endl;
print(a,sz,sz);
return 0;
}

核心部分ShellSort中内层的while循环实现的是查找相应组内的插入位置,并提前进行位置的交换。而for循环控制的是从每个组内的第2个数开始重复在该组前面有序的数据表中实现直接插入排序。与直接插入排序的区别是shell插入排序一次for将所有组内的第i个数插入到各自前i-1个有序表中。

输出为:

Initial array
13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 -------------
13 14 94 33 82 25 59 94
65 23 45 27 73 25 39 10 ==>
13 14 45 27 73 25 39 10
65 23 94 33 82 25 59 94 current array
13 14 45 27 73 25 39 10 65 23 94 33 82 25 59 94 ----------------
13 14 45
27 73 25
39 10 65
23 94 33
82 25 59
94
==>
13 10 25
23 14 33
27 25 45
39 73 59
82 94 65
94
current array
13 10 25 23 14 33 27 25 45 39 73 59 82 94 65 94 ----------------
13
10
25
23
14
33
27
25
45
39
73
59
82
94
65
94 ==>
10
13
14
23
25
25
27
33
39
45
59
65
73
82
94
94 current array
10 13 14 23 25 25 27 33 39 45 59 65 73 82 94 94 ----------------
Sorted array
10 13 14 23 25 25 27 33 39 45 59 65 73 82 94 94

算法分析

  1. 增量序列的选择

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

    好的增量序列的共同特征:

    • 最后一个增量必须为1;
    • 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。

      有人通过大量的实验,给出了目前较好的结果:当n较大时,比较和移动的次数约在nl.25到1.6nl.25之间。
  2. Shell排序的时间性能优于直接插入排序

    希尔排序的时间性能优于直接插入排序的原因:

    • 当数据表初态基本有序时直接插入排序所需的比较和移动次数均较少。
    • 当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。
    • 在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di−1作为距离排过序,使数据表较接近于有序状态,所以新的一趟排序过程也较快。

      因此,希尔排序在效率上较直接插人排序有较大的改进。
  3. 稳定性

    希尔排序是不稳定的。两个相同关键字在排序前后的相对次序是可能发生变化的。

这个方法对于大的数据集效率其实并不高,但是它是一个对小数量数据表(小于1000)进行排序的最快算法之一。另外,相对使用的内存较少。


2015-9-24 艺少

排序算法三:Shell插入排序的更多相关文章

  1. python实现排序算法三:插入排序

    插入排序基本思想:假设一个无序数组A,则对于只有一个元素A[0]的子数组C来讲,其是有序的,然后将A[1]插入到C中,则就是将A[1]与A[0]进行比较,如果A[1]比A[0]小,则交换两者的顺序,这 ...

  2. Java常见排序算法之Shell排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  3. Java常见排序算法之直接插入排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  4. Java常见排序算法之折半插入排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  5. 排序算法之直接插入排序Java实现

    排序算法之直接插入排序 舞蹈演示排序: 冒泡排序: http://t.cn/hrf58M 希尔排序:http://t.cn/hrosvb  选择排序:http://t.cn/hros6e  插入排序: ...

  6. 七内部排序算法汇总(插入排序、Shell排序、冒泡排序、请选择类别、、高速分拣合并排序、堆排序)

    写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的随意序列,又一次排列成一个按keyword有序的序列.因此排序掌握各种排序算法很重要. 对以下介绍的各个排序,我们假定全部排 ...

  7. 我的Java开发学习之旅------>Java经典排序算法之二分插入排序

    一.折半插入排序(二分插入排序) 将直接插入排序中寻找A[i]的插入位置的方法改为采用折半比较,即可得到折半插入排序算法.在处理A[i]时,A[0]--A[i-1]已经按关键码值排好序.所谓折半比较, ...

  8. IOS算法(三)之插入排序

    直接插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其keyword大小插入到前面已经排好序的子序列中的适当位置,直到所有记录插入完毕为止. 设数组为a[0-n-1]. ...

  9. 结构-行为-样式-Js排序算法之 直接插入排序

    最新因工作原因需要接触到算法,之前学习C++的时候有接触过算法,Javascript中实现算法其实也是大同小异.下面我讲下第一个实现的排序算法--直接插入排序.基本实现思路:假定一个数组中前n(n&g ...

随机推荐

  1. Hadoop集群分布搭建

    一.准备工作 1.最少三台虚拟机或者实体机(官网上是默认是3台),我这边是3台 s1: 10.211.55.18 s2: 10.211.55.19 s3: 10.211.55.20 2.安装JDK 3 ...

  2. React应用数据传递的方式

    1. props属性 典型的React应用,数据通过props按照自上而下(父->子)的顺序传递数据. 2. Context传值 1. 应用场景 对于一些应用中全局性的属性(如UI主题.语言.登 ...

  3. Spring AOP的作用,动态代理模式

    AOP即面向切面编程.AOP是基于代理模式的. 代理模式: 当我们需要修改一个类,在类中加入代码时,为了不破坏这个类的封装性.可以使用代理模式,建立一个代理类. 比如:修改需求,在调用UserCont ...

  4. linux系列(二十二):tar命令

    1.命令格式 tar[必要参数][选择参数][文件] 2.命令功能 用来压缩和解压文件.tar本身不具有压缩功能.他是调用压缩功能实现的 3.命令参数 必要参数: -A 新增压缩文件到已存在的压缩 - ...

  5. CSPS模拟94

    我好菜啊...... %%%迪神AK 虽然考试成绩不太好,但至少能想到正解了,也不会菜到打不出暴力. T1:想了半天不会,发现直接打高精可以拿到80分,就赶紧码完扔了,结果正解是利用double避免了 ...

  6. codeforces425C

    http://codeforces.com/contest/425/problem/C 题意:两数列a[],b[],进行若干轮操作,每次操作花费e, 将a的一个前缀和b的一个前缀(两前缀的最后一个数字 ...

  7. base/7/x86_64/filelists_db FAILED

      解决办法: [root@localhost ~]# cd /var/lib/rpm [root@localhost rpm]# rm -rf __db.* # 清除原 rpmdb 文件 [root ...

  8. (转)服务端监控工具:nmon的使用

    在性能测试过程中,对服务端的各项资源使用情况进行监控是很重要的一环.这篇博客,介绍下服务端监控工具:nmon的使用方法.. 一.认识nmon 1.简介 nmon是一种在AIX与各种Linux操作系统上 ...

  9. Debian/Ubuntu/CentOS开机启动

    说明:常用的Linux启动项就是在/etc/rc.local的exit 0语句之间添加启动脚本,另一种方法,使用update-rc.d命令添加/禁止开机启动项. 在centos7中增加脚本有两种常用的 ...

  10. ngx.shared.DICT.set

    ngx.shared.DICT.set 原文: ngx.shared.DICT.set syntax: success, err, forcible = ngx.shared.DICT:set(key ...