构建堆的算法

Algorithm that builds heap

本文关键字:算法 构建      更新时间:2023-10-16

我正在尝试实现创建堆的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);
}

实际上,该表是通过越界索引访问的。

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

我想你在这种情况下指的是&&

下一个r分支相同。

如果您仍然有问题,下面是我自己的实现,您可以使用作为参考。它也是基于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;
    }
};