在c ++中实现二进制堆

时间:2018-03-24 16:02:45

标签: c++ data-structures heap

我想在C ++中实现Max-Heap数据结构。必须动态分配它以尽可能少地占用内存。我为它编写了两个函数,Push和Heapify(基于Cormen的算法简介),但是对于输入1,3,5,7我得到的堆看起来像5; 1; 3; 7(所以7是一个人的儿子,我无法找到我犯错的地方。

int parent(int i) { return (i - 1) / 2; }
int left(int i) { return 2 * i + 1; }
int right(int i) { return 2 * i + 2; }

// Inserting element into heap
void Push(int val) {

    int *tmp = new int[size + 1];
    int i = 0;
    for (i; i < size; i++) tmp[i] = arr[i];
    tmp[size] = val; // Insert as leaf
    delete[] arr;
    arr = new int[size + 1];
    arr = tmp;
    size++;
    Heapify(arr, 0);
}

void Heapify(int *arr, int i) {

    int largest, tmp;
    int l = left(i);
    int r = right(i);
    if ((l <= size) && (arr[l] > arr[i])) largest = l;
    else largest = i;
    if ((r <= size) && (arr[r] > arr[largest])) largest = r;
    if (largest != i) {
        tmp = arr[i];
        arr[i] = arr[largest];
        arr[largest] = tmp;
        Heapify(arr, largest);
    }
}

编辑:这些是Heap类中的方法

1 个答案:

答案 0 :(得分:0)

您的代码和算法存在多个问题:

算法问题

Heapify方法的作用是维护节点的堆属性,其中左右子树已经是max-heaps,只有节点本身可能违反堆属性。您错误地使用它将密钥插入堆中。您需要使用IncreaseKey将新密钥插入堆中:

void IncreaseKey(int index, int value) {
    arr[index] = value;
    int parentIndex;
    while(index > 0 && arr[(parentIndex = parent(index))] < arr[index]){
        int tmp = arr[parentIndex];
        arr[parentIndex] = arr[index];
        arr[index] = tmp;
        index = parentIndex;
    }
}

并且Push方法变为:

void Push(int val) {
    int *tmp = new int[size + 1];
    for (int i = 0; i < size; i++)
        tmp[i] = arr[i];
    delete[] arr;
    arr = tmp;
    size++;
    IncreaseKey(size-1, val);
}

您的代码问题

Heapify方法中,您有以下条件:

if ((l <= size) && ...

if ((r <= size) && ...

<=应更改为<,因为您在致电size之前已增加Heapify

您的代码中还存在其他问题:

  • 最好更改一下:

    int i = 0;
    for (i; i < size; i++) tmp[i] = arr[i];
    

    到此(#1):

    for (int i; i < size; i++) tmp[i] = arr[i];
    

    或者这个(但上面的代码仍然更好,因为它限制了ifor语句的范围)(#2):

    int i = 0;
    for (; i < size; i++) tmp[i] = arr[i];
    

    它们之间没有功能差异,但是for循环的第一部分没有做任何事情,并且在循环之后你也不需要i。所以#1是最好的。

  • 这些方面存在一个更微妙的问题:

    arr = new int[size + 1];
    arr = tmp;
    

    您分配了一个内存,并且没有释放它,重新分配了变量,并丢失了已分配内存的地址。 tmp已经分配给您分配的内存,因此请删除第一行,然后您就可以了。