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
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;
}
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
If you're looking for the algorithm implementation try searching Github.
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.
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.