通用的最小堆(最大堆)D-ary Heap

听说有一种最小(大)堆,不限于是完全二叉树,而是完全D叉树,名为D-ary Heap(http://en.wikipedia.org/wiki/D-ary_heap)。D可以是1,2,3,4,100,对于优先队列该有的功能都没有问题。

动手写一个D-ary Heap,应该不难。简单起见,不考虑像STL一样通过template传入Comp类,下面的实现要求T类型重载了operator <和operator >。

template<class T>
class DaryHeap
{
    size_t D;
    size_t size;
    vector<T> a;
    ...
};

用vector容器存储数据,是因为在优先队列的插入、构建、删除操作需要RandomAccessIterator,而使用deque或其他STL容器都将影响性能。

为了节约点访问vector::size()函数的代价,用size_t size记录堆的大小。这也许没有必要,因为编译器可能对size()的调用做优化,而且访问size()的次数也并不多。

然后写堆的基本操作,即元素的上移下移。完全D叉树的性质和二叉树差不多,甚至可以推广到1叉树(数组)。

    void up(size_t i)
    {
        while(i)
        {
            size_t p = (i-1)/D;
            if(a[p]>a[i])
            {
                swap(a[p], a[i]);
                i = p;
            }
            else break;
        }
    }
    void down(size_t i)
    {
        size_t ii;
        size_t min = i*D+1;
        while(min<size)
        {
            for(ii=i*D+2; ii<size; ii++)
                if(a[min] > a[ii]) min = ii;
            if(a[min]<a[i])
            {
                swap(a[min], a[i]);
                i = min;
                min = i*D+1;
            }
            else break;
        }
    }

写好了这两个函数,堆的插入删除排序构建就都一样了:

    DaryHeap(int _D=2):size(0)
    {
        if(_D<1) D=1;
        else D=_D;
    }
    size_t getsize(){return size;}
    void push(T& x)
    {
        a.push_back(x);
        up(size++);
    }
    T& top()
    {
        if(size)
            return a[0];
    }
    void pop()
    {
        if(size)
        {
            a[0] = a[--size];
            a.pop_back();
            down(0);
        }
    }

最后测试:

main()
{
    DaryHeap<int> h(10);
    for(int i=10; i>0; i--)
    {
        h.push(i);
  //      h.print();
    }
    for(int i=10; i>0; i--)
    {
        cout <<h.top()<<ends;
        h.pop();

    }
}

D-ary Heap的定义是:

1  逻辑上是一个完全多叉树;

2  每个父节点有最多D个子节点;

3  子节点永远比父节点大(小),前提是节点具有可比性。

性质:

1  父节点=(子节点-1)/D;

2  子节点=父节点*D+i (i=1, 2, ..., D);

操作:

1  插入时将新插入元素放在最尾端,并与父节点交换位置直到比父节点大,即up操作。

2  从一个数组a构建成一个D-ary Heap,即需要每一个a[i](i>1)做如上的up操作。

3  删除一个节点时,将尾部的节点复制到待删除节点的位置,size-=1,然后将新复制节点从待删除节点开始向下移动,直到所有的子节点都比新复制节点大,down操作。至于怎么求子节点中最小的那个,要么去构建个局部的最小堆,要么就只好遍历咯。

4  排序:每一次将堆的根节点与尾节点a[size-1]交换,同时size-=1,再调整新根节点的位置(就是将堆首删除后拿到数组尾端。)

总的来说,和熟为人知的二叉树除了up和down有一点点不同,其他的一模一样。

时间: 2024-09-30 19:05:14

通用的最小堆(最大堆)D-ary Heap的相关文章

优先队列及最小堆最大堆

为什么优先队列里默认是堆(heap)实现,默认是优先级高的出队,定义结构体重载函数为什么要按照从小到大排序?原来是自己对优先队列还不太了解: 1 堆 1.1 简介 n个关键字序列Kl,K2,-,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质): (1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n),当然,这是小根堆,大根堆则换成>=号.//k(i)相当于二叉树的非叶结点,K(2i)则是左孩子,k(2i+1)是右孩子 若将此序列所存储的向量R[1..n]看做是一

最小堆_最大堆

在大数查找中会遇到一类问题,例如在100亿条数据中找出 最大的(最小的) 前1000个元素.以int型4Byte为例,有1*1010*4 B = 4*1010/(230) B = 37.25G. 直接读取到内存中显然不合适,那么就需要: 首先,读取前1000个元素,建立一个最小堆(最大堆): 其次,之后每读取一个元素就与最小堆根元素(1000个数中最小值)进行比较: 如果,新元素大于(小于)堆顶元素 则,删除堆顶元素,将新元素插入堆顶.然后调整堆序,删除堆顶....循环往复 #define le

Google 面试题:Java实现用最大堆和最小堆查找中位数 Find median with min heap and max heap in Java

Google面试题 股市上一个股票的价格从开市开始是不停的变化的,需要开发一个系统,给定一个股票,它能实时显示从开市到当前时间的这个股票的价格的中位数(中值). SOLUTION 1: 1.维持两个heap,一个是最小堆,一个是最大堆. 2.一直使maxHeap的size大于minHeap. 3. 当两边size相同时,比较新插入的value,如果它大于minHeap的最大值,把它插入到minHeap.并且把minHeap的最小值移动到maxHeap. ...具体看代码 1 /*********

Black Box--[优先队列 、最大堆最小堆的应用]

Description Our Black Box represents a primitive database. It can save an integer array and has a special i variable. At the initial moment Black Box is empty and i equals 0. This Black Box processes a sequence of commands (transactions). There are t

C++ priority_queue 最大堆、最小堆

问题描述 通常在刷题的时候,会遇到最大堆.最小堆的问题,这个时候如果自己去实现一个也是OK的,但是通常时间不太够,那么如何处理?这时,就可以借助C++ STL的priority_queue. 具体分析 需要注意的是,C++ STL默认的priority_queue是将优先级最大的放在队列最前面,也即是最大堆.那么如何实现最小堆呢? 假设有如下一个struct: struct Node { int value; int idx; Node (int v, int i): value(v), idx

最大堆(最小堆)

最大堆是一种很有用的数据结构,它是一颗完全二叉树,并且如果一个节点有儿子节点,其关键字都不小于其儿子节点的关键字.(最小树反之:节点值不大于儿子节点的完全二叉树.) 最大堆使用的一个典型的地方就是找出无序数字中,最大的一个数字.比如100亿整数中找出最小的前100个数字,典型的解决方案之一就是:先去处前边一百个值,创建一个最大堆,然后顺序读入的剩下的每个值,如果值小于根节点值,则删除根节点,把这个值插入,重建最大堆.重复这过程.最后就得到了最小的前100个数字(如果找前100个最大的值,就建立一

最小堆和最大堆的JAVA实现

/** * 文件名:BinaryHeap.java * 时间:2014年11月3日下午7:15:34 * 作者:修维康 */ package chapter6; import java.util.*; /** * 类名:BinaryHeap 说明:建立一个最小堆 */ class MinHeap<AnyType extends Comparable<? super AnyType>> { private int currentSize; private static final i

C++ multiset通过greater、less指定排序方式,实现最大堆、最小堆功能

STL中的set和multiset基于红黑树实现,默认排序为从小到大. 定义三个multiset实例,进行测试: multiset<int, greater<int>> greadterSet; multiset<int, less<int>> lessSet; multiset<int> defaultSet; for (int i = 0; i < 10; i++) { int v = int(arc4random_uniform(10

最大堆,最小堆及堆排序

基本概念: 1.完全二叉树:若二叉树的深度为h,则除第h层外,其他层的结点全部达到最大值,且第h层的所有结点都集中在左子树. 2.满二叉树:满二叉树是一种特殊的的完全二叉树,所有层的结点都是最大值. 定义: 1.堆是一颗完全二叉树: 2.堆中的某个结点的值总是大于等于(最大堆)或小于等于(最小堆)其孩子结点的值. 3.堆中每个结点的子树都是堆树. 堆的数据结构如下: struct MaxHeap { EType *heap; //存放数据的空间,下标从1开始存储数据,下标为0的作为工作空间,存储