希尔算法简介                                                                                                                                       

常见排序算法一般按平均时间复杂度分为两类:
O(n^2):冒泡排序、选择排序、插入排序
O(nlogn):归并排序、快速排序、堆排序

简单排序时间复杂度一般为O(n^2),如冒泡排序、选择排序、插入排序等
高级排序时间复杂度一般为O(nlogn),如归并排序、快速排序、堆排序。
两类算法随着排序集合越大,效率差异越大,在数量规模1W以内的排序,两类算法都可以控制在毫秒级别内完成,但当数量规模达到10W以上后,简单排序往往需要以几秒、分甚至小时才能完成排序;而高级排序仍可以在很短时间内完成排序。

今天所讲的希尔排序是从插入排序进化而来的排序算法,也属于高级排序,只不过时间复杂度为O(n^1.5),略逊于其他几种高级排序,但也远远优于O(n^2)的简单排序了。希尔排序没有明显的短板,不像归并排序需要大量的辅助空间,也不像快速排序在最坏的情况下和平均情况下执行效率差别比较大,且代码简单,易于实现。
一般在面对中等规模数量的排序时,可以优先使用希尔排序,当发现执行效率不理想时,再改用其他高级排序。

实际测试做了各个高级排序对大数据量排序的耗时对比(没错,冒泡排序就是拿出来搞笑的..),可以看到希尔排序的效率比其他几种O(nlogn)的高级排序差了几倍了,1W个数以下规模的排序这种差异还可以忽略不计的;但当数据规模超过10W以上时,可以很明显看到希尔排序效率跟其他高级排序差了很多。这种效率差距随着数据规模变大,会越来越大。

总结来说:希尔排序对中等大小规模数据表现良好,对规模非常大的数据排序不是最优选择。

算法稳定性:不稳定

基本概念                                                                                                                                        

什么是增量?
增量也称步长。做个形象比喻:一个书架放着一排书,现在我们每数X本书就拿出一本,这个变量X就称之为增量。

希尔排序原理                                                                                                                                  
教科书式表述:
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
大白话表述:
仍然拿上述例子做比喻:一个书架放着一排书,现在从第一本书起每数X本书,就在那本书上贴红色贴纸,贴完红色贴纸后,再次从第二本书起每数X本书就贴上蓝色贴纸(跟之前颜色不同即可),重复贴纸过程,直到所有书都贴满贴纸。接着对有相同颜色贴纸的书做插入排序。然后撕掉所有贴纸后重新对书进行贴纸,这次则每数Y本书就贴纸(Y>X),所有书贴满后再进行插入排序。重复贴纸排序、贴纸排序这个过程,直到最后每数1本书就贴纸(也就是每本书都贴同样颜色贴纸),再插入排序为止。

过程图示                                                                                                                                        

实现代码                                                                                                                                        

#include "stdafx.h"
#include <iostream>
#include <ctime>
using namespace std; int a[]; #define BEGIN_RECORD \
{ \
clock_t ____temp_begin_time___; \
____temp_begin_time___=clock(); #define END_RECORD(dtime) \
dtime=float(clock()-____temp_begin_time___)/CLOCKS_PER_SEC;\
} /*
希尔插入排序过程
a - 待排序数组
s - 排序区域的起始边界
delta - 增量
len - 待排序数组长度
*/
void shellInsert(int a[], int s, int delta, int len)
{
int temp, i, j, k;
for (i = s + delta; i < len; i += delta)
{
for(j = i - delta; j >= s; j -= delta)
if(a[j] < a[i])break; temp = a[i];
for (k = i; k > j; k -= delta)
{
a[i] = a[i - delta];
}
a[k + delta] = temp;
}
} /*
希尔排序
a - 待排序数组
len - 数组长度
*/
void shellSort(int a[], int len)
{
int temp;
int delta; //增量 //Hibbard增量序列公式
delta = (len + )/ - ; while(delta > ) //不断改变增量,对数组迭代分组进行直接插入排序,直至增量为1
{
for (int i = ; i < delta; i++)
{
shellInsert(a, i, delta, len);
}
delta = (delta + )/ - ;
} } void shellSort2(int a[], int len)
{
int temp;
int delta; //增量 //希尔增量序列公式
delta = len / ; while(delta > )
{
for (int i = ; i < delta; i++)
{
shellInsert(a, i, delta, len);
}
delta /= ;
} } void printArray(int a[], int length)
{
cout << "数组内容:";
for(int i = ; i < length; i++)
{
if(i == )
cout << a[i];
else
cout << "," << a[i]; }
cout << endl;
} int _tmain(int argc, _TCHAR* argv[])
{
float tim;
int i; for (i = ; i < ; i++)
{
a[i] = int(rand() % );
} cout << "10W个数的希尔排序:" << endl; for (i = ; i < ; i++)
{
a[i] = int(rand() % );
}
BEGIN_RECORD shellSort2(a, sizeof(a)/sizeof(int)); END_RECORD(tim) cout << "希尔增量序列运行时间:" << tim << "s" << endl; for (i = ; i < ; i++)
{
a[i] = int(rand() % );
}
BEGIN_RECORD shellSort(a, sizeof(a)/sizeof(int)); END_RECORD(tim) cout << "Hibbard增量序列运行时间:" << tim << "s" << endl; system("pause");
return ;
}

希尔排序的效率                                                                                                                              
希尔排序的增量序列是影响希尔排序效率的最关键因素,至今为止还没有一个最完美的增量序列公式。可究竟应该选取什么样的增量才是最好,目前还是一个数学难题。

看如下两个增量序列:

n/2、n/4、n/8...1

1、3、7...2^k-1

第一个序列称为希尔增量序列,使用希尔增量时,希尔排序在最坏情况下的时间复杂度为O(n*n)。

第二个序列称为Hibbard增量序列,使用Hibbard增量时,希尔排序在最坏情况下的时间复杂度为O(n^3/2)。

对10W个无序数分别以希尔增量序列、Hibbard增量序列进行希尔排序,耗时比较如图所示,在10W量级的排序,Hibbard增量序列比希尔增量序列的效率已经高了几倍。尽管Hibbard并不是最完美的增量序列,但表现已经非常不错,因此在实际应用中希尔排序多采用Hibbard增量序列。

处理海量数据的高级排序之——希尔排序(C++)的更多相关文章

  1. 排序算法--希尔排序(Shell Sort)_C#程序实现

    排序算法--希尔排序(Shell Sort)_C#程序实现 排序(Sort)是计算机程序设计中的一种重要操作,也是日常生活中经常遇到的问题.例如,字典中的单词是以字母的顺序排列,否则,使用起来非常困难 ...

  2. 《Algorithm算法》笔记:元素排序(2)——希尔排序

    <Algorithm算法>笔记:元素排序(2)——希尔排序 Algorithm算法笔记元素排序2希尔排序 希尔排序思想 为什么是插入排序 h的确定方法 希尔排序的特点 代码 有关排序的介绍 ...

  3. 学习C#之旅 冒泡排序,选择排序,插入排序,希尔排序[资料收集]

    关于冒泡排序,选择排序,插入排序,希尔排序[资料收集]  以下资料来源与网络 冒泡排序:从后到前(或者从前到后)相邻的两个两两进行比较,不满足要求就位置进行交换,一轮下来选择出一个最小(或最大)的放到 ...

  4. 插入排序、冒泡排序、选择排序、希尔排序、高速排序、归并排序、堆排序和LST基数排序——C++实现

    首先是算法实现文件Sort.h.代码例如以下: <pre name="code" class="java">/* * 实现了八个经常使用的排序算法: ...

  5. C数据结构排序算法——希尔排序法用法总结(转http://www.cnblogs.com/skywang12345/p/3597597.html)

    希尔排序介绍 希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进.该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 希尔排序实质上是一种分组插入方法.它 ...

  6. 数据结构和算法(Golang实现)(22)排序算法-希尔排序

    希尔排序 1959 年一个叫Donald L. Shell (March 1, 1924 – November 2, 2015)的美国人在Communications of the ACM 国际计算机 ...

  7. 使用 js 实现十大排序算法: 希尔排序

    使用 js 实现十大排序算法: 希尔排序 希尔排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  8. 希尔排序及希尔排序java代码

    原文链接:http://www.orlion.ga/193/ 由上图可看到希尔排序先约定一个间隔(图中是4),然后对0.4.8这个三个位置的数据进行插入排序,然后向右移一位对位置1.5.9进行插入排序 ...

  9. 冒泡排序 & 选择排序 & 插入排序 & 希尔排序 JavaScript 实现

    之前用 JavaScript 写过 快速排序 和 归并排序,本文聊聊四个基础排序算法.(本文默认排序结果都是从小到大) 冒泡排序 冒泡排序每次循环结束会将最大的元素 "冒泡" 到最 ...

随机推荐

  1. 15 个 Android 通用流行框架大全

      1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Android Universal Image Loader 一个强大的加载,缓存,展 ...

  2. LVS 三种工作模式原理、以及优缺点比较(转载)

    原文地址:http://9ilinux.com/149.html 一.NAT模式(VS-NAT) 原理:就是把客户端发来的数据包的IP头的目的地址,在负载均衡器上换成其中一台RS的IP地址,并发至此R ...

  3. Android 蹲坑的疑难杂症集锦一

    各位看官老爷子你们好,我就是那个挖坑不埋,还喜欢开新矿的小喵同志. 问大家一个问题,在Github上找项目的时候,看到中文简介说明你们是不是觉得这个项目很low不屑一顾? 最近朋友无意中说,在Gith ...

  4. 关于解决haswell赛扬和奔腾 不能安装的问题

    打开EFI\CLOVER\config.plist,并找到KernelAndKextPatches字段,在子集内插入下面代码. <key>FakeCPUID</key> < ...

  5. JAVA Day7

    6  方法   1.格式[访问控制符] void返回值类型 方法名(参数列表:数据类型 参数名); 2.类的方法: *用来定义类的某种行为或功能 * 3.方法的返回值 *如果有返回值,方法中必须要使用 ...

  6. poj 1651 Multiplication Puzzle (区间dp)

    题目链接:http://poj.org/problem?id=1651 Description The multiplication puzzle is played with a row of ca ...

  7. BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊 ——Link-Cut Tree

    [题目分析] 以前用分块的方法做过这道题目,现在再用LCT水一边,发现思路确实巧妙. 每次弹射,可以看作在一条边上走了过去,而且很重要的性质,每一个点的出边只有一条. 那么就很容易知道,可以用LCT维 ...

  8. css3 -- 背景图处理

    1.多背景图片: p{ background-image:url() , url(); background-position:95% 90% , 50% 50%; background-repect ...

  9. android访问网络--okhttp

    import com.squareup.okhttp.MediaType;import com.squareup.okhttp.OkHttpClient;import com.squareup.okh ...

  10. 两个app 的合并

    我们需要把两个app 合并在一起,就是在原有项目基础上添加一个功能使用.如下有项目a和项目b: 一开始,我们把项目b独立成一个module,然后,作为一个库给项目a调用. 问题是,项目b 已有的app ...