希尔算法简介                                                                                                                                       

常见排序算法一般按平均时间复杂度分为两类:
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. [Oracle] PL/SQL学习笔记

    -- 1. 使用一个变量 declare -- Local variables here v_name ); begin -- Test statements here select t.user_n ...

  2. 浅学JSON——Json.NET之首次试手

    首次遭遇Json格式,缘由项目中用到Json数据,需要进行解析,为此,将Json数据转为了自己较为熟悉的DataTable格式,以此展示至DataGridView中,验证是否成功. 直接上代码: // ...

  3. 第二十篇:在SOUI中使用分层窗口

    从Windows 2K开始,MS为UI开发引入了分层窗口这一窗口风格.使用分层窗口,应用程序的主窗口可以是半透明,也可以是逐点半透明(即每一个像素点的透明度可以不同). 可以说,正是因为有了分层窗口, ...

  4. C# 使用 NPOI 库读写 Excel 文件

    NPOI 是开源的 POI 项目的.NET版,可以用来读写Excel,Word,PPT文件.在处理Excel文件上,NPOI 可以同时兼容 xls 和 xlsx.官网提供了一份 Examples,给出 ...

  5. NSFileManager 的基本使用方法

    本方法已有个人总结, int main(int argc, const char * argv[]) { @autoreleasepool { NSString *path=@"/Users ...

  6. IM即时通讯实现原理

      即时通讯(Instant Messenger,简称IM)软件多是基于TCP/IP和UDP进行通讯的,TCP/IP和UDP都是建立在更低层的IP协议上的两种通讯传输协议.前 者是以数据流的形式,将传 ...

  7. hashlib加密操作模块

    import hashlib#加密操作obj=hashlib.md5(bytes("hasdfghjklcxz",encoding="utf-8"))#加密操作 ...

  8. 端口偷窃(Port Stealing)技术

    端口偷窃(Port Stealing)技术   该技术主要用于局域网中间人攻击中,尤其目标计算机采用静态ARP后,导致ARP欺骗无效.   背景知识:路由器为了方便转发数据包,会在内部记录每个接口和M ...

  9. MFC 打开链接的方法

    第一种: system("start explorer http://http://www.baidu.com"); 第二种: ShellExecute(NULL, NULL, _ ...

  10. Ue4 BatteryCollector 教程笔记

    H UFUNCTION(BlueprintNativeEvent) void EventName(); virtual void EventName_Implementation(); EventNa ...