porgarmingduod
porgarmingduod

Reputation: 7878

Is there a C++ MinMax Heap implementation?

I'm looking for algorithms like ones in the stl (push_heap, pop_heap, make_heap) except with the ability to pop both the minimum and maximum value efficiently. AKA double ended priority queue. As described here.

Any clean implementation of a double ended priority queue would also be of interest as an alternative, however this question is mainly about a MinMax Heap implementation.

My google-fu has not been fruitful, but surely, it must exist?

Upvotes: 15

Views: 13494

Answers (5)

Eugen Constantin Dinca
Eugen Constantin Dinca

Reputation: 9130

If you're looking for the algorithm implementation try searching Github.

Upvotes: 2

Vinod Kumar
Vinod Kumar

Reputation: 489

Sorry for lengthy code but it works fine except it may complicate to read and may contain some unnecessary variables and I am not uploading the Insert function. Use it as include .h file.

#include <math.h>
#define bool int
#define true 1
#define false 0
#define Left(i) (2 * (i))
#define Right(i) (2 * (i) + 1)
#define Parent(i) ((i) / 2)

void TrickleDown(int* A, int n)
{
    int i;
    for (i = 1; i <= n / 2; i++)
    {

        if (isMinLevel(i, n) == true)
            TrickleDownMin(A, i, n);
        else
            TrickleDownMax(A, i, n);
        Print(A, n);
        printf("i = %d\n", i);
    }
}

int isMinLevel(int i, int n)//i is on min level or not
{
    int h = 2;
    if (i == 1)
        return true;
    while (true)
    {
        if (i >= pow(2, h) && i <= pow(2, h + 1) - 1)
            return true;
        else if (i > n || i < pow(2, h))
            return false;
        h += 2;
    }
}

void swap(int* a, int* b)
{
    *a ^= *b;
    *b ^= *a;
    *a ^= *b;
}

void TrickleDownMin(int* A, int i, int n)
{
    int m, lc, rc, mc, lclc, lcrc, mlc, rclc, rcrc, mrc;
    int child;
    lc = Left(i);
    if (lc > n) // A[i] has no children
        return;
    else
    {
        rc = Right(i);
        mc = rc > n ? lc : (A[lc] > A[rc]) ? rc : lc;
        child = true; // keep tracking m comes from children or grandchildren
        // m = smallest of children and grand children
        lclc = Left(lc);
        if (lclc <= n)
        {
            lcrc = Right(lc);
            mlc = lcrc > n ? lclc :(A[lclc] > A[lcrc]) ? lcrc : lclc;
            mc = mlc > mc ? mc : mlc;
            if (mc == mlc)
                child = false;
        }
        rclc = Left(rc);
        if (rclc <= n)
        {
            rcrc = Right(rc);
            mrc = rcrc > n ? rclc : (A[rclc] > A[rcrc]) ? rcrc : rclc;
            mc = mrc > mc ? mc : mrc;
            if (mc == mrc)
                child = false;
        }
        m = mc;
        if (!child)//m is one of the child of i
        {
            if (A[m] < A[i])
            {
                swap(&A[m], &A[i]);
                if (A[m] > A[Parent(m)])
                    swap(&A[m], &A[Parent(m)]);
                TrickleDownMin(A, i, m);
            }
        }
        else    //m is child of i
        {
            if (A[m] < A[i])
                swap(&A[i], &A[m]);
        }

    }
}

void TrickleDownMax(int* A, int i, int n)
{
    int m, lc, rc, mc, lclc, lcrc, mlc, rclc, rcrc, mrc;
    int child;
    lc = Left(i);
    if (lc > n)//A[i] has no children
        return;
    else
    {
        rc = Right(i);
        mc = rc > n ? lc : (A[lc] < A[rc]) ? rc : lc;
        child = true; //keep tracking m comes from choldren or grandchildren
        //m = greatest of children and grand children
        lclc = Left(lc);
        if (lclc <= n)
        {
            lcrc = Right(lc);
            mlc = lcrc < n ? lclc : (A[lclc] < A[lcrc]) ? lcrc : lclc;
            mc = mlc < mc ? mc : mlc;
            if (mc == mlc)
                child = false;
        }
        rclc = Left(rc);
        if (rclc <= n)
        {
            rcrc = Right(rc);
            mrc = rcrc < n ? rclc : (A[rclc] < A[rcrc]) ? rcrc : rclc;
            mc = mrc < mc ? mc : mrc;
            if (mc == mrc)
                child = false;
        }
        m = mc;
        if (!child)//m is one of the child of i
        {
            if (A[m] > A[i])
            {
                swap(&A[m], &A[i]);
                if (A[m] < A[Parent(m)])
                    swap(&A[m], &A[Parent(m)]);
                TrickleDownMax(A, i, m);
            }
        }
        else      //m is child of i
        {
            if (A[m] > A[i])
                swap(&A[i], &A[m]);
        }

    }
}

void Print(int* a, int n)
{
    int i;
    for (i = 1; i < n + 1; i++)
    {
        printf("%d  ", a[i]);
    }

}

int DeleteMin(int* A, int n)
{
    int min_index = 1;
    int min = A[1];
    swap(&A[min_index], &A[n]);
    n--;
    TrickleDown(A, n);
    return min;
}

int DeleteMax(int* A, int n)
{
    int max_index, max;
    max_index = n < 3 ? 2 : (A[2] > A[3]) ? 2 : 3;
    max = A[max_index];
    swap(&A[max_index], &A[n]);
    n--;
    TrickleDown(A, n);
    return max;
}

Upvotes: -2

Sergey
Sergey

Reputation:

Not sure if this is exactly what you're looking for, but here is a MinMax Heap i created back in my university days. This was part of a larger project so, there is an extraneous reference on a 'Stopwatch' class which measured performance. I'm not including this class as it isn't my work. It isn't hard to strip it out so i'm leaving the reference to it as it is.

The code on snipplr

To use, just create a new instance of the heap with whatever type you want to use. (Note, custom types would need to overload comparison operators). Create array of that type and then pass it to the constructor and specify the current array size and what the maximum should be. This implementation works on top of a passed array only since this is the only thing i needed, but you have everything you need to implement push and pop methods.

Upvotes: 0

Martin
Martin

Reputation: 12403

I can't find any good implementations, but since no one else can either I'm guessing you'll be writing your own, in which case I have a few handy references for you.

A paper that no one seems to have mentioned is the original proposition for Min-Max-Heaps:

http://www.cs.otago.ac.nz/staffpriv/mike/Papers/MinMaxHeaps/MinMaxHeaps.pdf

I've implemented a min-max heap from this paper twice (not in C) and found it fairly trivial.

An improvement, which I haven't ever implemented, is a Min-Max-Fine-Heap. I can't find any good papers or references on a plain old fine heap, but I did find one on the min-max-fine-heap, which apparently performs better:

http://arxiv.org/ftp/cs/papers/0007/0007043.pdf

Upvotes: 4

JonM
JonM

Reputation: 840

Is there a reason you can't use std::set? It sounds like that, along with some wrappers to access and remove set::begin() and --set::end() will solve the problem. I imagine it will be difficult to find something that can generally do a MinMax Heap much faster than the default implementation of set.

Upvotes: 7

Related Questions