Существует ли реализация C ++ MinMax Heap? - PullRequest
13 голосов
/ 12 февраля 2010

Я ищу алгоритмы, подобные тем, которые есть в stl (push_heap, pop_heap, make_heap), за исключением возможности эффективно выталкивать минимальное и максимальное значения. AKA двусторонняя приоритетная очередь. Как описано здесь .

Любая чистая реализация очереди с двусторонним приоритетом также будет представлять интерес в качестве альтернативы, однако этот вопрос в основном касается реализации MinMax Heap.

Мой гугл-фу не был плодотворным, но наверняка он должен существовать?

Ответы [ 6 ]

6 голосов
/ 12 февраля 2010

Есть ли причина, по которой вы не можете использовать std::set? Похоже, что наряду с некоторыми обертками для доступа и удаления set::begin() и --set::end() решит проблему. Я полагаю, что будет трудно найти что-то, что может сделать кучи MinMax намного быстрее, чем стандартная реализация set.

4 голосов
/ 17 февраля 2010

Я не могу найти хороших реализаций, но так как никто другой не может, я думаю, вы будете писать свои собственные, в этом случае у меня есть несколько полезных ссылок для вас.

Статья, которую, кажется, никто не упомянул, является первоначальным предложением для Min-Max-Heaps:

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

Я реализовал кучу min-max из этой статьи дважды (не в C) и нашел ее довольно тривиальной.

Улучшение, которое я никогда не реализовывал, - это Min-Max-Fine-Heap. Я не могу найти ни одной хорошей статьи или ссылки на простую старую кучу, но я нашел одну в min-max-fine-heap, которая, очевидно, работает лучше:

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

3 голосов
/ 12 февраля 2010
1 голос
/ 17 февраля 2010

Если вы ищете реализацию алгоритма, попробуйте напрямую Поиск кода Google .

0 голосов
/ 23 июня 2013

Извините за длинный код, но он работает нормально, за исключением того, что он может усложнить чтение и может содержать некоторые ненужные переменные, и я не загружаю функцию Вставить. Используйте это как include .h файл.

#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;
}
0 голосов
/ 21 февраля 2010

Не уверен, что это именно то, что вы ищете, но вот MinMax Heap, которую я создал еще в студенческие годы. Это было частью более крупного проекта, поэтому существует ссылка на класс «Секундомер», который измерял производительность. Я не включаю этот класс, так как это не моя работа. Это не трудно удалить, поэтому я оставляю ссылку на это как есть.

код на snipplr

Чтобы использовать, просто создайте новый экземпляр кучи с любым типом, который вы хотите использовать. (Обратите внимание, что пользовательские типы должны будут перегружать операторы сравнения). Создайте массив этого типа, а затем передайте его конструктору и укажите текущий размер массива и максимальный размер. Эта реализация работает поверх переданного массива только потому, что это единственное, что мне нужно, но у вас есть все необходимое для реализации методов push и pop.

...