构建堆的算法

时间:2014-03-15 23:06:02

标签: c++ algorithm

我正在尝试实现创建堆的build_max_heap函数(因为它是用Cormen的“引入算法”编写的)。但我得到了奇怪的错误,我无法将其本地化。我的程序成功地将随机数提供给表,显示它们但是在build_max_heap()之后我得到了奇怪的数字,这可能是因为某个地方我的程序到达了表格之外的东西,但我找不到这个错误。我会很高兴得到任何帮助。

例如,我得到了表格:

0 13 18 0 22 15 24 19 5 23

我的输出是:

24 7 5844920 5 22 15 18 19 0 23

我的代码:

#include <iostream>
#include <ctime>
#include <stdlib.h>  
const int n = 12; // the length of my table, i will onyl use indexes 1...n-1
struct heap
{
    int *tab;
    int heap_size;
};
void complete_with_random(heap &heap2)
{
    srand(time(NULL));
    for (int i = 1; i <= heap2.heap_size; i++)
    {
        heap2.tab[i] = rand() % 25;
    }
    heap2.tab[0] = 0;
}
void show(heap &heap2)
{
    for (int i = 1; i < heap2.heap_size; i++)
    {
        std::cout << heap2.tab[i] << " ";
    }
}
int parent(int i)
{
    return i / 2;
}
int left(int i)
{
    return 2 * i;
}
int right(int i)
{
    return 2 * i + 1;
}
void max_heapify(heap &heap2, int i)
{
    if (i >= heap2.heap_size || i == 0)
    {
        return;
    }
    int l = left(i);
    int r = right(i);
    int largest;
    if (l <= heap2.heap_size || heap2.tab[l] > heap2.tab[i])
    {
        largest = l;
    }
    else
    {
        largest = i;
    }
    if (r <= heap2.heap_size || heap2.tab[r] > heap2.tab[i])
    {
        largest = r;
    }
    if (largest != i)
    {
        std::swap(heap2.tab[i], heap2.tab[largest]);
        max_heapify(heap2, largest);
    }
}
void build_max_heap(heap &heap2)
{
    for (int i = heap2.heap_size / 2; i >= 1; i--)
    {
        max_heapify(heap2, i);
    }
}
int main()
{
    heap heap1;
    heap1.tab = new int[n];
    heap1.heap_size = n - 1;
    complete_with_random(heap1);
    show(heap1);
    std::cout << std::endl;
    build_max_heap(heap1);
    show(heap1);
}

2 个答案:

答案 0 :(得分:2)

实际上,使用越界索引访问该表。

if (l <= heap2.heap_size || heap2.tab[l] > heap2.tab[i])
                         ^^

我认为在这种情况下你的意思是&&

对于r的下一个分支也一样。

答案 1 :(得分:1)

如果您仍然遇到问题,以下是我自己的实施,您可以将其用作参考。它也是基于Cormen等人。因为它使用了或多或少相同的术语。它可能具有实际容器,比较和交换功能的任意类型。它提供了一个类似于公共队列的接口,包括密钥递增。

因为它是更大的软件集合的一部分,所以它使用了一些未在此定义的实体,但我希望算法仍然清晰。 CHECK只是一种断言机制,你可以忽略它。您也可以忽略swap成员,只使用std::swap

代码的某些部分使用基于1的偏移,其他部分基于0,并且转换是必需的。每种方法的上述评论都表明了这一点。

template <
    typename T,
    typename ARRAY = array <T>,
    typename COMP = fun::lt,
    typename SWAP = fun::swap
>
class binary_heap_base
{
protected:

    ARRAY a;
    size_t heap_size;

    SWAP swap_def;
    SWAP* swap;

    // 1-based
    size_t parent(const size_t n) { return n / 2; }
    size_t left  (const size_t n) { return n * 2; }
    size_t right (const size_t n) { return n * 2 + 1; }

    // 1-based
    void heapify(const size_t n = 1)
    {
        T& x = a[n - 1];
        size_t l = left(n);
        size_t r = right(n);
        size_t select =
            (l <= heap_size && COMP()(x, a[l - 1])) ?
            l : n;
        if (r <= heap_size && COMP()(a[select - 1], a[r - 1]))
            select = r;
        if (select != n)
        {
            (*swap)(x, a[select - 1]);
            heapify(select);
        }
    }

    // 1-based
    void build()
    {
        heap_size = a.length();
        for (size_t n = heap_size / 2; n > 0; n--)
            heapify(n);
    }

    // 1-based
    size_t advance(const size_t k)
    {
        size_t n = k;
        while (n > 1)
        {
            size_t pn = parent(n);
            T& p = a[pn - 1];
            T& x = a[n - 1];
            if (!COMP()(p, x)) break;
            (*swap)(p, x);
            n = pn;
        }
        return n;
    }

public:

    binary_heap_base() { init(); set_swap(); }
    binary_heap_base(SWAP& s) { init(); set_swap(s); }

    binary_heap_base(const ARRAY& a) { init(a); set_swap(); }
    binary_heap_base(const ARRAY& a, SWAP& s) { init(a); set_swap(s); }

    void init() { a.init(); build(); }
    void init(const ARRAY& a) { this->a = a; build(); }

    void set_swap() { swap = &swap_def; }
    void set_swap(SWAP& s) { swap = &s; }

    bool empty() { return heap_size == 0; }

    size_t size() { return heap_size; }

    size_t length() { return heap_size; }

    void reserve(const size_t len) { a.reserve(len); }

    const T& top()
    {
        CHECK (heap_size != 0, eshape());
        return a[0];
    }

    T pop()
    {
        CHECK (heap_size != 0, eshape());
        T x = a[0];
        (*swap)(a[0], a[heap_size - 1]);
        heap_size--;
        heapify();
        return x;
    }

    // 0-based
    size_t up(size_t n, const T& x)
    {
        CHECK (n < heap_size, erange());
        CHECK (!COMP()(x, a[n]), ecomp());
        a[n] = x;
        return advance(n + 1) - 1;
    }

    // 0-based
    size_t push(const T& x)
    {
        if (heap_size == a.length())
            a.push_back(x);
        else
            a[heap_size] = x;
        return advance(++heap_size) - 1;
    }

};