【问题标题】:What is wrong with my C++ heap implementation?我的 C++ 堆实现有什么问题?
【发布时间】:2021-12-30 20:09:20
【问题描述】:

我正在尝试为在线法官实现堆结构。我对实现非常满意,它支持我所有的测试用例,但在线法官拒绝了它。

插入函数追加新元素,然后将其冒泡到二叉树中。 removeMax 函数将向量中最大的元素替换为最后一个元素,然后将其冒泡。

vector<int> heap;

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

int getSize(){
    return heap.size();
}

void insert(int element){
    heap.push_back(element);
    int i = heap.size() - 1;

    while(element > heap[i / 2]) {
        swap(heap[i], heap[i / 2]);
        i = i / 2;
    }
}

void removeMax(){
    heap[0] = heap[heap.size() - 1];
    heap.pop_back();
    int i = 0;
    int iGreater = heap[i * 2] > heap[i * 2 + 1] ? i * 2 : i * 2 + 1;

    while(i < heap.size() &&  heap[i] < heap[iGreater]) {
        swap(heap[i], heap[iGreater]);
        i = iGreater;
        iGreater = heap[i * 2] > heap[i * 2 + 1] ? i * 2 : i * 2 + 1;
    }
}

【问题讨论】:

  • 在你的insert函数中,如果新元素的索引在ii/2之间会发生什么?
  • 如果heap 包含两个或更少的元素,removeMax 会导致未定义的行为。
  • 要使 i/2 技巧起作用,您可能需要从索引 1 开始堆。
  • 你确定heap 是一个全局变量吗?哪个是在线评委?你能引用代码挑战吗?
  • 问题来自 Kattis,ID 为 heap

标签: c++ binary-tree heap


【解决方案1】:

您正在使用堆方程:

  • 节点 i 的父节点是节点 i/2
  • 节点 i 的子节点是节点 2*i 和 2*i + 1

仅当您使用基于 1 的数组索引时才有效(索引 1 是数组的第一个元素)

但是 C++ 对向量(和数组)使用基于 0 的索引,所以这不起作用。你需要

  • 节点 i 的父节点是节点 (i-1)/2
  • 节点 i 的子节点是节点 2*i + 1 和 2*i + 2

您的 removeMax 结束条件也是错误的,导致您跑出向量的末尾并获得未定义的行为。

【讨论】:

    【解决方案2】:

    几个问题:

    • 在零索引向量中,索引为i 的节点的子节点位于i * 2 + 1i * 2 + 2。索引为i 的节点的父节点位于(i - 1) / 2

    • insert 函数中的while 循环在到达根节点时必须退出,因为根没有父节点。所以i &gt; 0 也应该是一个循环条件。

    • removeMax 应首先确保堆不为空,否则heap[heap.size() - 1] 将有未定义的行为。

    • 在分配给iGreater 之前,应首先确保当前节点有子节点,否则像heap[i * 2 + 1] 这样的表达式将具有未定义的行为。还应该预见一个节点只有一个孩子的情况。

    这里是一个更正:

    void insert(int element){
        heap.push_back(element);
        int i = heap.size() - 1;
    
        while (i > 0 && element > heap[(i - 1) / 2]) {
            swap(heap[i], heap[(i - 1) / 2]);
            i = (i - 1) / 2;
        }
    }
    
    void removeMax(){
        if (heap.size() == 0) {
            return;
        }
        heap[0] = heap[heap.size() - 1];
        heap.pop_back();
        int i = 0;
    
        while (i * 2 + 1 < heap.size()) {
            int iGreater = i * 2 + 1;
            if (iGreater + 1 < heap.size() && heap[iGreater + 1] > heap[iGreater]) {
                iGreater++;
            }
            if (heap[i] >= heap[iGreater]) {
                break;
            }
            swap(heap[i], heap[iGreater]);
            i = iGreater;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-07
      • 2021-07-25
      • 2011-09-08
      • 2016-05-28
      • 1970-01-01
      • 1970-01-01
      • 2017-09-16
      • 2012-06-14
      相关资源
      最近更新 更多