处理海量数据的高级排序之——堆排序(C++)
在面对大数据量的排序时(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++)的更多相关文章
- 处理海量数据的高级排序之——希尔排序(C++)
希尔算法简介 ...
- 处理海量数据的高级排序之——归并排序(C++)
代码实现 ...
- 处理海量数据的高级排序之——快速排序(C++)
代码实现 ...
- javascript数据结构与算法--高级排序算法
javascript数据结构与算法--高级排序算法 高级排序算法是处理大型数据集的最高效排序算法,它是处理的数据集可以达到上百万个元素,而不仅仅是几百个或者几千个.现在我们来学习下2种高级排序算法-- ...
- IOS- 快速排序,冒泡排序,直接插入排序和折半插入排序,希尔排序,堆排序,直接选择排序
/*******************************快速排序 start**********************************///随即取 当前取第一个,首先找到第一个的位置 ...
- 数据结构和算法 – 11.高级排序算法(上)
对现实中的排序问题,算法有七把利剑可以助你马道成功. 首先排序分为四种: 交换排序: 包括冒泡排序,快速排序. 选择排序: 包括直接选择排序,堆排序. 插入排序 ...
- 有k个list列表, 各个list列表的元素是有序的,将这k个列表元素进行排序( 基于堆排序的K路归并排序)
解题思路: 排序方法:多路归并排序 每次将n个list的头元素取出来,进行排序(堆排序),最小元素从堆中取出后,将其所在list的下一个元素 放入堆中,调整堆序列. 函数实现原型: void list ...
- 七内部排序算法汇总(插入排序、Shell排序、冒泡排序、请选择类别、、高速分拣合并排序、堆排序)
写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的随意序列,又一次排列成一个按keyword有序的序列.因此排序掌握各种排序算法很重要. 对以下介绍的各个排序,我们假定全部排 ...
- Java数据结构和算法 - 高级排序
希尔排序 Q: 什么是希尔排序? A: 希尔排序因计算机科学家Donald L.Shell而得名,他在1959年发现了希尔排序算法. A: 希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插 ...
随机推荐
- C++ list的基本操作和使用
转自:http://blog.sina.com.cn/s/blog_6a4aa98201012fhn.html Lists将元素按顺序储存在链表中. 与 向量(vectors)相比, 它允许快速的插入 ...
- 上四条只是我目前总结菜鸟们在学习FPGA时所最容易跑偏的地
长期以来很多新入群的菜鸟们总 是在重复的问一些非常简单但是又让新手困惑不解的问题.作为管理员经常要给这些菜鸟们普及基础知识,但是非常不幸的是很多菜鸟怀着一种浮躁的心态来学习 FPGA,总是急于求成. ...
- 在SharePoint2010中用out-of-box的方式自定制Application Pages(AccessDenied,Confirmation,Error,Login,RequestAccess,Signout,WebDeleted)
在实际项目中需要对SharePoint2010中的AccessDenied页面进行自定制,于是乎上网搜索相关内容,经实际操作此方法可行,便以此文记录. 在SharePoint2010中,由于secur ...
- 【RQNOJ356】myt的格斗
题目描述 ’恩 ~~这个和这个也是朋友.把他们放在一起......哇!终于完成了’mty费了好大劲,终于找出了一支最为庞大的军队. fyc很高兴,立马出征与人fight.mty万万没想到fyc竟然把他 ...
- 【项目总结】之——JS分割字符串
背景: 在我们做那个招标项目的时候,由于是刚刚接触到这个BS东西,我基本上是什么也不会.可是当时组长浩哥给过我一个任务,就是叫我将数据里面以字符串形式存在的信息切割开,然后显示到前台上去.当时对于浩哥 ...
- Android Studio在导入eclipse的项目时一直卡在gradle:Configure project
学Java的时候用的是eclipse,写android代码的时候用了疯狂android讲义推荐的AS.在用AS的时候出了很多问题,比如我想从别人那里拷贝eclipse写的工程的时候就遇到了Gradle ...
- 关于main函数传参数的问题
argc是命令行总的参数个数 argv[]是argc个参数,其中第0个参数是程序的全名,以后的参数 命令行后面跟的用户输入的参数,比如: int main(int ...
- SQL.WITH AS.公用表表达式(CTE)(转)
一.WITH AS的含义 WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候,是 ...
- springMVC 的工作原理和机制(转)
工作原理上面的是springMVC的工作原理图: 1.客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web. ...
- 分享Kali Linux 2016.2第47周镜像
分享Kali Linux 2016.2第47周镜像Kali Linux官方于11月20日发布Kali Linux 2016.2的第47周镜像.这次发布仍然包含11个镜像文件.其中,不仅包含Gnome桌 ...