【问题标题】:Implementing min Heap using an array [closed]使用数组实现最小堆[关闭]
【发布时间】:2018-02-19 18:55:29
【问题描述】:

我正在尝试在 C 中实现最小堆。

// Heaps:
// node i -> 2i and 2i+1 children
// 2i//2 = i and 2i+1//2 = i same parents

#include <stdio.h>
#include <stdlib.h>

#define max 100

int heap[max];
int size = 0;

void heapifyUp(){ // last element
    int i = size;

    while(i){ // 
        int parent = i/2;
        if (heap[parent]<heap[i]){
            int t = heap[parent];
            heap[parent] = heap[i];
            heap[i]=t;
        }        
    }
}

void heapifyDown(){ // top element
    int i = 0;

    while(i<=size){
        int c1 = 2*i;
        int c2 = 2*i + 1;
        int t = 0;
        if (heap[c1]>=heap[c2]){
            t = c2;
        }
        else{
            t = c1;
        }
        int temp = heap[i];
        heap[i] = heap[t];
        heap[t] = temp;
        i = t;
    }
}

void insert(int key){
    size = size + 1;
    heap[size] = key;
    heapifyUp();
}

int returnMin(){
    return heap[0];
}

int deleteMin(){
    int t = heap[0];
    heap[0] = heap[size];
    size = size - 1;
    heapifyDown();
    return t;
}

void printHeap(){

    int i = 0;
    while(i<=size){
        printf("%d",heap[i]);
        i = i + 1;
    }
}

int main(){
    insert(10);
    insert(20);
    insert(11);
    insert(7);
    insert(18);

    printHeap();
    printf("%d",deleteMin());

    insert(110);
    insert(-7);
    insert(15);

    printf("%d",deleteMin());
}

问题是当我运行程序时,我没有得到任何输出,程序也没有终止。

我认为我已经正确地实现了逻辑。

使用 C 调试器很难,因为我在 Mac 上(不支持代码块,从来没有真正理解如何使用 gdb,我只是在文本编辑器上使用内置的 gcc 编译器),所以我被困在这个问题。

感谢您的帮助。

【问题讨论】:

  • 如果你用 C 写这个,你为什么要标记 C++? Mac 也有自己的免费 IDE,称为 XCode(在其中调试应该很容易)——更不用说除了 CodeBlocks 之外还有很多其他选项
  • @UnholySheep 因为在这种情况下 c plus plus 的实现也是相同的......除了包含......和打印语法......没有 xcode 我在启动板中搜索它
  • 如果您没有调试器,您可以随时在代码中使用printf 语句来告诉您发生了什么。当你进入“现实世界”时,你将不得不经常使用这种东西。
  • “从来没有真正理解过如何使用 gdb”——嗯,现在是学习的最佳时机。 SO 不能替代学习调试器。如果您在使用 gdb 时遇到问题,请随时提出相关问题。

标签: c algorithm data-structures heap


【解决方案1】:

在 heapifyUp 你有一个while(i) 声明。 "i" 被初始化为 1 并且永远不会被修改。而且您在该循环中没有任何“返回”或“中断”。所以条件永远成立。

【讨论】:

  • 设置 i = 父级;在那个循环中没有对程序进行任何更改...
  • 首先,我会听从 UnholySheep 的建议并获得一个免费的 Mac 版 C++ IDE 以便能够进行调试。它使事情变得容易多了。调试器是开发人员拥有的最强大的工具之一。其次,我会将size=size+1 放在插入的末尾,而不是开头,因为您在数组中留下了 0(这在调试器中很容易看到)。最后,我猜当heapifyup中的if为真时,你想更新i,但是当if为假时,也许你应该尝试从那个函数返回
【解决方案2】:

您的代码存在一些问题,以下是其中的几个:
1. 正如 Jorge 所说,在您的 heapifyUp() 函数中,您永远不会上升,它只是停留在那里并进入无限循环。
2. 在heapifyDown() 函数中出现越界问题。您需要检查其子代是否有效。而且逻辑有问题。
3. 另外,请决定您是要使用 0 索引数组还是 1 索引数组。因为您的某些函数认为它是 0 索引的,而有些函数认为它是 1 索引的。我根据 1 个索引数组进行了更正。如果你愿意,我可以将其更改为 0 索引或者它可能是你的作业。

我已经尽力了,但还是有一些地方需要改正:

#include <stdio.h>
#include <stdlib.h>

#define max 100

int heap[max];
int size = 0;

void heapifyUp(){ // last element
    int i = size;

    while(1){ // 
        int parent = i/2;
        if (parent > 0 && heap[parent] > heap[i]){
            int t = heap[parent];
            heap[parent] = heap[i];
            heap[i]=t;
            i = parent;
        } else {
            break;
        }
    }
}

void heapifyDown(){ // top element
    int i = 1;

    while(i<size){
        int c1 = 2*i;
        int c2 = 2*i + 1;
        int t;
        if (c1 <= size) {
            t = c1;
        } else {
            break;
        }
        if (c2 <= size && heap[c1] > heap[c2]){
            t = c2;
        }

        if(heap[i] >= heap[t]) break;

        int temp = heap[i];
        heap[i] = heap[t];
        heap[t] = temp;
        i = t;
    }
}

void insert(int key){
    size = size + 1;
    heap[size] = key;
    heapifyUp();
}

int returnMin(){
    return heap[1];
}

int deleteMin(){
    int t = heap[1];
    heap[1] = heap[size];
    size = size - 1;
    heapifyDown();
    return t;
}

void printHeap(){
    int i = 1;
    while(i <= size){
        printf("%d ", heap[i]);
        i++;
    }
    printf("\n");
}

int main()
{
    insert(10);
    insert(20);
    insert(11);
    insert(7);
    insert(18);

    printHeap();
    printf("%d\n",deleteMin());

    insert(110);
    insert(-7);
    insert(15);

    printHeap();
    printf("%d\n",deleteMin());
    return 0;
}

【讨论】:

  • 是的,索引是这里的重要说明。从子索引计算父索引和反之亦然的更简单的数学依赖于 1 索引数组。
  • 在我的回答中,我说您需要决定索引,但没有什么可决定的。在 C 编程中,您始终必须使用 0。
  • 我打算同意您在回答中关于索引的声明。然而,当谈到在 C 中的索引时,虽然数组自然索引为 0,但它在内存中的存在方式是正确的,但有一些方法可以绕过它。可以选择只接受浪费存储的“第 0 个”元素并忽略它,而是将堆的第一个元素放置在 arr[1]。另一种解决方法是创建一个指向数组前一个元素的内存地址的指针,这个ptr[1] 将引导你到arr[0]
猜你喜欢
  • 2020-02-23
  • 2021-11-27
  • 2016-07-05
  • 1970-01-01
  • 2010-11-09
  • 1970-01-01
  • 2014-08-14
  • 2015-08-17
  • 2021-12-30
相关资源
最近更新 更多