在面对大数据量的排序时(100W以上量级数据),通常用以下三种的排序方法效率最高O(nlogn):快速排序、归并排序,堆排序。在这个量级上,其他冒泡,选择,插入等简单排序已经无法胜任,效率极低,跟前面三种排序差了千百倍,因此不作比较。

这三种排序的平均时间复杂度均为O(nlogn),快速排序,归并排序在面对基本有序序列排序时,效率反会降低。且归并排序需要用到O(n)的临时存储空间。而堆排序没有明显缺点,特别在面对经常会插入新元素的排序需求,堆排序效果最好。

下面是三种排序对100W个无序数组进行排序的时间对比,可以看出在平均情况下,时间效率:快排>归并>堆排序

基础概念                                                                                                                                                                                                       

什么是堆?

:一种数据结构,全称为:二叉堆数据结构,是一种数组对象。

当所有节点都大于各自左右子节点时,叫大顶堆;

当所有节点都小于各自左右子节点时,叫小顶堆。

在堆排序中,使用大顶堆结构。

排序原理                                                                                                                                                                                                       

若输出堆顶的最大值之后,使得剩余n-1个元素的序列重新又建成一个堆,则得到n个元素中个次大值。如此反复执行,便能得到一个有序序列,这个过程就称之为堆排序。

因此堆排序的实现思路,可以细分为两部分:

1、如何将一个无序数组排列成大顶堆(建堆过程)

2、拿走最大值后如何从剩下的堆中找出次大值,重新建立大顶堆(筛选过程)

时间复杂度                                                                                                                                                                                                    

堆排序可分细分为两部分:建堆过程+排序过程。

建堆过程时间复杂度为O(n),即将一个无序数组建立成堆只需要线性时间。

排序过程需要对n个数据进行筛选时,每次筛选需要O(logn)时间,所以整个排序过程的时间为O(nlogn)

因此堆排序总的运行时间为: O(nlogn) = O(n) + O(nlogn)

算法实现                                                                                                                                                                                                        

#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;\
} /*
目标:筛选区域为以索引i为树根的子树,找出该子树最大值,将其存放到索引i
过程:从索引为i的结点开始往下,与较大的子节点交换值,向下搜索直到子树底部
a - 待排序数组
i - 筛选起始结点索引
len - 排序元素数量
*/
void sift(int a[], int i, int len)
{
int temp = a[i];
int j = * i; while(j <= len)
{
if(j < len && a[j] < a[j+]) //如果右结点比左结点大,则拿右结点跟父节点比较
j++;
if(a[i] < a[j]) //如果子节点比父节点大,则两者交换值,子节点成为新的父节点,继续向下筛选
{
a[i] = a[j];
a[j] = temp;
i = j;
j = * i;
}
else //如果父节点比子节点大,则说明找到了该子树的最大值,结束筛选
{
break;
}
}
a[i] = temp;
} /*
堆排序(大顶堆)
a - 待排序的数组
len - 数组长度
*/
void heapSort(int a[], int len)
{
int temp;
int i; for (i = len-; i > ; i--) //堆排序只能从下标为1开始排序,因此要把数组所有数据后一移位。下标0的数据不处理
{
a[i] = a[i - ];
} for (i = len/; i >= ; i--) //建堆过程(使得全树的父节点都比子节点大)
{
sift(a, i, len);
}
for (i = len - ; i >= ; i--) //排序过程:每次从树根取值(该值必为最大值),放到树的最后一个结点n,并把该结点从树中移除。重复排序过程,直到将所有结点从树移除,排序结束
{
temp = a[];
a[] = a[i];
a[i] = temp;
sift(a, , i - ); //从树根取出最大值,取最尾树结点放到树根,此时树根不再为最大值,需要再对树根进行一次筛选过程,以确保树根仍然为最大值
}
} 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;
BEGIN_RECORD //int a[1000000];
for (int i = ; i < ; i++)
{
a[i] = int(rand() % );
} //printArray(a, sizeof(a)/sizeof(int));
heapSort(a, sizeof(a)/sizeof(int));
//printArray(a, sizeof(a)/sizeof(int)); END_RECORD(tim) cout << "运行时间:" << tim << "s" << endl; system("pause");
return ;
}

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

  1. 处理海量数据的高级排序之——希尔排序(C++)

    希尔算法简介                                                                                              ...

  2. 处理海量数据的高级排序之——归并排序(C++)

    代码实现                                                                                                 ...

  3. 处理海量数据的高级排序之——快速排序(C++)

    代码实现                                                                                                 ...

  4. javascript数据结构与算法--高级排序算法

    javascript数据结构与算法--高级排序算法 高级排序算法是处理大型数据集的最高效排序算法,它是处理的数据集可以达到上百万个元素,而不仅仅是几百个或者几千个.现在我们来学习下2种高级排序算法-- ...

  5. IOS- 快速排序,冒泡排序,直接插入排序和折半插入排序,希尔排序,堆排序,直接选择排序

    /*******************************快速排序 start**********************************///随即取 当前取第一个,首先找到第一个的位置 ...

  6. 数据结构和算法 – 11.高级排序算法(上)

      对现实中的排序问题,算法有七把利剑可以助你马道成功. 首先排序分为四种:       交换排序: 包括冒泡排序,快速排序.       选择排序: 包括直接选择排序,堆排序.       插入排序 ...

  7. 有k个list列表, 各个list列表的元素是有序的,将这k个列表元素进行排序( 基于堆排序的K路归并排序)

    解题思路: 排序方法:多路归并排序 每次将n个list的头元素取出来,进行排序(堆排序),最小元素从堆中取出后,将其所在list的下一个元素 放入堆中,调整堆序列. 函数实现原型: void list ...

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

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

  9. Java数据结构和算法 - 高级排序

    希尔排序 Q: 什么是希尔排序? A: 希尔排序因计算机科学家Donald L.Shell而得名,他在1959年发现了希尔排序算法. A: 希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插 ...

随机推荐

  1. sql语句中----删除表数据的"三兄弟"

    说到删除表数据的关键字,大家记得最多的可能就是delete了 然而我们做数据库开发,读取数据库数据.对另外的两兄弟用得就比较少了 现在来介绍另外两个兄弟,都是删除表数据的,其实也是很容易理解的 老大- ...

  2. 利用Aspose.Word控件和Aspose.Cell控件,实现Word文档和Excel文档的模板化导出

    我们知道,一般都导出的Word文档或者Excel文档,基本上分为两类,一类是动态生成全部文档的内容方式,一种是基于固定模板化的内容输出,后者在很多场合用的比较多,这也是企业报表规范化的一个体现. 我的 ...

  3. JavaScript设计模式——工厂模式

    工厂模式:是一种实现“工厂”概念的面上对象设计模式.实质是定义一个创建对象的接口,但是让实现这个接口的类来决定实例化哪个类.工厂方法让类的实例化推迟到子类中进行.创建一个对象常常需要复杂的过程,所以不 ...

  4. 记一次小团队Git实践(下)

    在上篇中,我们已经能基本使用git了,接下来继续更深入的挖掘一下git. 更多的配置自定义信息 除了前面讲的用户名和邮箱的配置,还可以自定义其他配置: # 自定义你喜欢的编辑器,可选 git conf ...

  5. Codeforces Round #355 (Div. 2)-C

    C. Vanya and Label 题目链接:http://codeforces.com/contest/677/problem/C While walking down the street Va ...

  6. redis 的使用 ( set集合类型操作)

    set 集合类型 释义:            redis 的 set 是 string 类型的无序集合 set 元素最大可以包含(2的32次方-1)个元素 关于 set 集合类型除了基本的添加删除操 ...

  7. eclipse 异常Unhandled event loop exception解决办法

    http://blog.csdn.net/leiswpu/article/details/26712709

  8. iOS实现简书的账号识别方式(正则表达式)

    通过简书iOS客户端登录,我们会看到请输入手机号或者邮箱登录,但是我们随机输入1234567的时候,便会弹出手机格式不正确,同样也会识别我们的邮箱格式,那么我们在项目中怎么实现这种判断呢? 0E471 ...

  9. BZOJ4537 : [Hnoi2016]最小公倍数

    将边按$a$从小到大排序,每$\sqrt{m}$个取一个关键点. 对于每个关键点,将这个点之前的边以及要在这个关键点回答的询问按$b$排序. 依次加入这个关键点之前的每条边,用并查集维护每个连通块$a ...

  10. Theano深度学习结构分析

    Reference:Theano入门三部曲 http://deeplearning.net/tutorial/logreg.html  (Softmax回归) http://deeplearning. ...