我的最大二进制堆中的 C++ 轮询操作工作得非常慢

标签 c++ data-structures heap priority-queue binary-heap

我正在用 C++ 实现最大二进制堆,它似乎工作正常。

但是,当我重复轮询操作(我的代码中的 delMax 方法)直到堆为空时,它花费的时间太长,它比构建堆本身要长,以防 10^ 7 个元素大约需要 6 秒,而我被告知几乎不需要时间。

此外,在打印堆摘要和打印删除时间之间,我打印了两次“Childless element!”(来自 leftChildrightChild方法),但我不知道这是从哪里来的,因为那里没有调用这些方法。

我的代码:

  #include "pch.h"
  #include <iostream>
  #include "time.h"
  #include <random>
  #include <string>
  #include <functional>
  #include <vector>
 using namespace std;
 template <typename T>
 class BinaryHeap;

template <typename T>
class BinaryHeap
{
vector <T> heap;
int getParent(int childInd)
{
    if (heap.size() == 0)
    {
        return -1;
    }
    //int parent = 0;
    int parent = floor((childInd - 1) / 2);
    if (heap.size() <= childInd)
    {
        cout << "No such element!" << endl;
        return -1;
    }
    else
        return parent;
}
int leftChild(int parentInd)
{
    int left = floor(2 * parentInd + 1);
    if (heap.size() <= parentInd)
    {
        cout << "Childless element!" << endl;
        return -1;
    }
    else
        return left;
}
int rightChild(int parentInd)
{
    int right = (2 * parentInd + 2);
    if (heap.size() <= parentInd)
    {
        cout << "Childless element!" << endl;
        return -1;
    }
    else
        return right;
}
void heapifydown(int index)
{
    int left = leftChild(index);
    int right = rightChild(index);
    int largest = index;
    if (heap.size() > left&&heap[left] > heap[index])
    {
        largest = left;
    }
    if (heap.size() > right&& heap[right] > heap[largest])
    {
        largest = right;
    }
    if (largest != index)
    {
        int temp = heap[index];
        heap[index] = heap[largest];
        heap[largest] = temp;
        heapifydown(largest);
    }
}
void heapifyup(int index)
{
    int p = getParent(index);
    if (heap.size() > index&& heap[p] < heap[index])
    {
        int temp = heap[index];
        heap[index] = heap[p];
        heap[p] = temp;
        heapifyup(p);
    }
}

public:
BinaryHeap() {};
~BinaryHeap()
{
    heap.clear();
}
void addElement(T el)
{
    heap.push_back(el);
    int index = heap.size() - 1;
    heapifyup(index);
}
void printHeap()
{
    if (heap.size() == 0)
    {
        cout << "Empty heap!" << endl;
        return;
    }
    for (int i = 0; i < heap.size(); i++)
    {

        cout << heap[i] << endl;
    }
}
T delMax()
{
    if (heap.size() == 0)
    {
        return -1;
    }
    T temp = heap[0];
    T temp2 = heap[0];
    heap[0] = heap.at(heap.size()-1);
    heap.pop_back();
    //T parent = 0;
    //T child = 2 * parent + 2;
    heapifydown(0);
    return temp;
    //delete &temp;
}
void clearHeap()
{
    for (int i = heap.size(); i > 0; --i)
    {
        heap.pop_back();
    }
}
void print()
{
    if (heap.size() == 0)
    {
        cout << "Empty heap!" << endl;
        return;
    }
    cout << "Size: " << heap.size()<<endl;
    cout << " Root: " << heap[0] << endl;
    cout << "L. child: " << heap[1] << endl;
    cout << "R. Child: " << heap[2] << endl;
    cout << "3 last elements: " << heap[heap.size()-3] <<
    " "<<heap[heap.size() - 2]<<
    " "<<heap[heap.size() - 1]<<endl;
}
};
int randomInt()
{
static default_random_engine generator{ 10 };
static uniform_int_distribution<int> rozklad{ 0, 11000000 };
static function<int()> los{ bind(rozklad, generator) };
int l = los();
return l;
}
int main()
{
BinaryHeap<int>*bh = new BinaryHeap<int>();
const int MAX_ORDER = 7; // maksymalny rzad wielkosci dodawanych danych
for (int i = 1; i <= MAX_ORDER; i++)
{
    const int n = pow(10, i);
    clock_t start1 = clock();
    for (int i = 0; i < n; i++)
    {
        int el = randomInt();
        bh->addElement(el);
    }
    clock_t stop1 = clock();
    double adding_time = (stop1 - start1) / (double)CLOCKS_PER_SEC;
    cout << "Adding time: " << adding_time << "s" << endl;
    bh->print();
    clock_t start2 = clock();
    for (int j = 0; j < n; j++)
    {
        int out = bh->delMax();
        //cout << "WyciagniEty: "<<bh->delMax()<<endl;
        //delete &out;
    }
    clock_t stop2 = clock();
    double polling_time = (stop2 - start2) / (double)CLOCKS_PER_SEC;
    cout << "Removing time: " << polling_time << "s" << endl;
    bh->print();
    bh->clearHeap();
}
delete bh;
return 0;
}

最佳答案

当父索引小于或等于堆大小时,“无子元素”消息可能会出现在 leftChildrightChild 函数中。通过检查您的代码,我会说当您尝试删除堆中的最后一个节点时会发生这种情况。考虑您的 delMax 函数(我已经删除了死代码和注释掉的代码):

T delMax()
{
    if (heap.size() == 0)
    {
        return -1;
    }
    T temp = heap[0];
    heap[0] = heap.at(heap.size()-1);
    heap.pop_back();
    heapifydown(0);
    return temp;
}

当堆大小为 1 时,调用 heap.pop_back() 删除最后一个元素,现在大小为 0。然后调用 heapifydown(0).

heapifydown 调用leftChildrightChild,它们都包含这段代码:

if (heap.size() <= parentInd)
{
    cout << "Childless element!" << endl;
    return -1;
}
else

heap.size() 返回 0,因为堆是空的。 parentInd 为 0,因为这是您传递的参数的值。因此,打印了“Childless element”。

令我感到惊讶的是代码竟然可以工作,因为 leftChildrightChild 都返回 -1,而 heapifyDown 没有t 检查返回值。结果,计算最大子节点的代码将报告 heap.size() > left,并将 heap[-1]heap 进行比较[0],并且可能会破坏程序的内存堆。这取决于数组开始之前内存中的内容。

我的建议是将您的 leftChild 函数修改为:

return (parentInd * 2) + 1;

并对rightChild做类似的修改。

在您的 heapifyDown 函数中,如果左 child 超出堆的边界则返回:

void heapifydown(int index) {
    int left;
    int right;
    int largest = index;

    left = leftChild(index);
    if (heap.size() <= left) {
        // left child index is outside range of the heap.
        // node has no children, so return.
        return;
    }

    if (heap[left] > heap[index]) {
        largest = left;
    }

    right = rightChild(index);
    if (heap.size() > right && heap[right] > heap[largest])
    {
        largest = right;
    }
    if (largest != index)
    {
        int temp = heap[index];
        heap[index] = heap[largest];
        heap[largest] = temp;
        heapifydown(largest);
    }
}

关于我的最大二进制堆中的 C++ 轮询操作工作得非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59075372/

相关文章:

c++ - Visual Studio : C++ Project Include Paths sharing over Repository

c++ - 带有 std::make_unique 的 push_back 或 emplace_back

go - 如何在 Go 中嵌入和覆盖结构

algorithm - 堆 - 对未知输入执行 DeleteMax 操作 - 实现

c++ - 使用可替换阶段在 C++ 中建模管道

java - 允许更改 key 的最大堆

c++ - 在包含 float 的结构上使用 memset()

c++ - 这个 typedef 定义是什么意思?

c++ - 在已排序的双向链表中插入节点

python - 将居中切片外的数组值清零