处理海量数据的三大排序之——堆排序(C++)

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

这三种排序的平均时间复杂度均为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[1000000];

#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 = 2 * i;

    while(j <= len)
    {
        if(j < len && a[j] < a[j+1])    //如果右结点比左结点大,则拿右结点跟父节点比较
            j++;
        if(a[i] < a[j])                 //如果子节点比父节点大,则两者交换值,子节点成为新的父节点,继续向下筛选
        {
            a[i] = a[j];
            a[j] = temp;
            i = j;
            j = 2 * i;
        }
        else                            //如果父节点比子节点大,则说明找到了该子树的最大值,结束筛选
        {
            break;
        }
    }
    a[i] = temp;
}

/*
堆排序(大顶堆)
a - 待排序的数组
len - 数组长度
*/
void heapSort(int a[], int len)
{
    int temp;
    int i;

    for (i = len-1; i > 0; i--)      //堆排序只能从下标为1开始排序,因此要把数组所有数据后一移位。下标0的数据不处理
    {
        a[i] =  a[i - 1];
    }

    for (i = len/2; i >= 1; i--)     //建堆过程(使得全树的父节点都比子节点大)
    {
        sift(a, i, len);
    }
    for (i = len - 1; i >= 2; i--)   //排序过程:每次从树根取值(该值必为最大值),放到树的最后一个结点n,并把该结点从树中移除。重复排序过程,直到将所有结点从树移除,排序结束
    {
        temp = a[1];
        a[1] = a[i];
        a[i] = temp;
        sift(a, 1, i - 1);        //从树根取出最大值,取最尾树结点放到树根,此时树根不再为最大值,需要再对树根进行一次筛选过程,以确保树根仍然为最大值
    }
}

void printArray(int a[], int length)
{
    cout << "数组内容:";
    for(int i = 0; i < length; i++)
    {
        if(i == 0)
            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 = 0; i < 1000000; i++)
    {
        a[i] = int(rand() % 100000);
    }

    //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 0;
}

处理海量数据的三大排序之——堆排序(C++),布布扣,bubuko.com

时间: 2024-08-08 21:49:34

处理海量数据的三大排序之——堆排序(C++)的相关文章

处理海量数据的三大排序之——归并排序(C++)

代码实现                                                                                                                                                                                   #include "stdafx.h" #include <iostream> #include <cti

处理海量数据的三大排序之——快速排序(C++)

代码实现                                                                                                                                                                                                        #include "stdafx.h" #include <iostream

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

希尔算法简介                                                                                                                                        常见排序算法一般按平均时间复杂度分为两类:O(n^2):冒泡排序.选择排序.插入排序O(nlogn):归并排序.快速排序.堆排序 简单排序时间复杂度一般为O(n^2),如冒泡排序.选择排序.插入排序等高级排序时间复杂

阿布学排序之堆排序

/** * 需求:堆排序的实现 * 知识储备: * 满二叉树:除叶子结点外的所有结点均有两个子结点,所有叶子结点必须在同一层上. * 完全二叉树: * 若二叉树的深度为h,除第h层外,其它各层(1~h-1)的节点数都达到最大个数,第h层所有结点都连续集中在最左边. * 完全二叉树是有满二叉树而引出来的,对于深度为K的,有N个结点的二叉树,当且仅当每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称它为完全二叉树. * * 二叉堆是完全二叉树或者是近似完全二叉树. * 二叉堆特性: *

排序值 堆排序

按照算法导论上的实现,不过把下标改成从0开始了. 原理: import java.util.Arrays; public class Solution { /** * 每次将堆顶元素交换到最后并从堆中除掉. * * @param a */ public static void heapSort(int[] a) { buildHeap(a); int n = a.length - 1; for (int i = a.length - 1; i > 0; i--) { swap(a, 0, i);

选择排序:堆排序

堆排序(Heap Sort):使用堆这种数据结构来实现排序. 先看下堆的定义: 最小堆(Min-Heap)是关键码序列{k0,k1,-,kn-1},它具有如下特性: ki<=k2i+1, ki<=k2i+2(i=0,1,-) 简单讲:孩子的关键码值大于双亲的. 同理可得,最大堆(Max-Heap)的定义: ki>=k2i+1, ki>=k2i+2(i=0,1,-) 同样的:对于最大堆,双亲的关键码值大于两个孩子的(如果有孩子). 堆的特点: 堆是一种树形结构,而且是一种特殊的完全二

排序 之 堆排序 归并排序

堆的概念 堆是具有下列性质的完全二叉树:每个节点的值都大于或等于其左右孩子结点的值,称为大顶堆:或着每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆. 堆排序 堆排序(Heap Sort)就是利用堆(假设利用大顶堆)进行排序的方法.它的基本思想是,将待排序的序列构造成一个大顶堆.此时,整个序列的最大值就是对顶的根结点.将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值.如此反复执行,就可以得到一个

排序算法2--简单选择排序、堆排序

一.简单选择排序和堆排序都属于选择排序 选择排序的思想是:每一趟从待排序的记录中选出关键字最小的记录,按顺序放在以排序的记录序列的后面,知道全部拍完为止. 二.简单选择排序(直接选择排序) 1.简单选择排序法是每次循环找出最值,循环结束后将最值调整到合适位置,交换的次数少. 每次找出当前无序队列中的最小的元素与第一个交换位置,再选择第二小的与第二个交换位置 原始队列:   3 5 6 2 4 1(最小元素1与3交换) 第一步: 1 5 6 2 4 3 (当前最小元素2与5交换) 第二步: 1 2

插入排序,希尔排序,堆排序详解

本文将介绍三种排序算法--插入排序,希尔排序,堆排序.本文所有例子都是使用升序 一.插入排序 算法思想 维护一个有序数组,将要插入的数据与有序数组自最后一个元素直到合适位置的数一一比较. eg: 有序数组:1,3,5,6,7   现在待插入数据为2,那么他将会和7,6,5,3,依次作比较,当带插入数据小于有序数组最后的元素大小,则将该元素后移,直到待插入元素找到合适位置为止. 代码实现 void InsertSort(int* a, int size) 02 { 03     assert(a)