从堆中移除

时间:2013-05-09 19:58:30

标签: c++ heap

我正在尝试使用这个堆。我插入一些随机数,然后删除它们以确保我的堆工作。问题是当我删除它们时,我得到堆中不应存在的重复数字。几乎我会插入以下数字并返回:5 2 10 10由于某种原因。

我的主要看起来像这样:

#include <iostream>
#include <fstream>
using namespace std;
#include "heap.h"

int main(void)
{
    Heap<int> inlist(4);
    inlist.insert(5);
    inlist.insert(2);
    inlist.insert(3);
    inlist.insert(10);
    int test;
    while(inlist.remove(test))
        cout << test << endl;
}

我的Heap看起来像这样:

#ifndef HEAP_H
#define HEAP_H

template<typename TYPE>
class Heap
{
    private:
        TYPE* heapData;
        int currSize;
        int capacity;
        void _siftUp(int);
        void _siftDown(int);
        int _leftChildOf(int) const;
        int _parentOf(int) const;

    public:
        Heap(int c = 100);
        ~Heap();
        bool viewMax(TYPE&) const;
        int getCapacity() const;
        int getCurrSize() const;
        bool insert(const TYPE&);
        bool remove(TYPE&);
};

template<typename TYPE>
Heap<TYPE>::Heap(int c = 100)
{
    capacity = 100;
    currSize = 0;
    heapData = new TYPE[capacity];
}

template<typename TYPE>
Heap<TYPE>::~Heap()
{
    delete[] heapData;
    currSize = 0;
    capacity = 0;
}

template<typename TYPE>
bool Heap<TYPE>::insert(const TYPE& dataIn)
{
    bool success = false;
    if(currSize < capacity)
    {
        heapData[currSize] = dataIn;
        _siftUp(currSize);
        currSize++;
        success = true;
    }
    return success;
}

template<typename TYPE>
void Heap<TYPE>::_siftUp(int child)
{
    TYPE temp;
    int parent;
    if(child > 0)
    {
        parent = _parentOf(child);
        if(heapData[child] > heapData[parent])
        {
            temp = heapData[parent];
            heapData[parent] = heapData[child];
            heapData[child] = temp;
            _siftUp(child);
        }
    }
}

template<typename TYPE>
bool Heap<TYPE>::remove(TYPE& dataOut)
{
    bool success = false;
    if(currSize > 0)
    {
        dataOut = heapData[0];
        currSize--;
        heapData[0] = heapData[currSize];
        _siftDown(0);
        success =  true;
    }
    return success;
}

template<typename TYPE>
void Heap<TYPE>::_siftDown(int parent)
{
    TYPE temp;
    int child = _leftChildOf(parent);
    if(child < currSize)
    {
        if((child + 1 < currSize) && (heapData[child] < heapData[child + 1]))
            child++;

        if(child)
        {
            temp = heapData[child];
            heapData[child] = heapData[child + 1];
            heapData[child + 1] = temp;
            _siftDown(child);
        }
    }
}

template<typename TYPE>
int Heap<TYPE>::_leftChildOf(int p) const
{
    return(2 * p + 1);
}

template<typename TYPE>
int Heap<TYPE>::_parentOf(int c) const
{
    return((c - 1) / 2);
}
//**************************************************************************
template<typename TYPE>
int Heap<TYPE>::getCapacity() const
{
    return capacity;
}

template<typename TYPE>
int Heap<TYPE>::getCurrSize() const
{
    return currSize;
}

template<typename TYPE>
bool Heap<TYPE>::viewMax(TYPE& max) const
{
    return false;
}
#endif

我很确定问题不在我插入堆时,而是当我将其移除时。

编辑我稍微更改了_siftDown - 现在数字显示5 10 3 2

if(child)
{
    temp = heapData[child];
    heapData[child] = heapData[parent];
    heapData[parent] = temp;
    _siftDown(child);
}

5 个答案:

答案 0 :(得分:2)

您的_siftDown已损坏,

template<typename TYPE>
void Heap<TYPE>::_siftDown(int parent)
{
    TYPE temp;
    int child = _leftChildOf(parent);
    if(child < currSize)
    {
        if((child + 1 < currSize) && (heapData[child] < heapData[child + 1]))
            child++;

        if(child)

这意味着检查什么? child此时2*parent + 12*parent + 2没有溢出,因为parent应始终为>= 0,这始终是正的〜&gt;条件得到满足。

您需要检查是否要交换heapData[parent]heapData[child],以便条件应为if (heapData[parent] < heapData[child])

        {
            temp = heapData[child];
            heapData[child] = heapData[child + 1];
            heapData[child + 1] = temp;

您正在交换索引childchild+1的元素,这是错误的。您应该在这里交换heapData[child]heapData[parent]

            _siftDown(child);
        }
    }
}

_siftUp

中也有错误
template<typename TYPE>
void Heap<TYPE>::_siftUp(int child)
{
    TYPE temp;
    int parent;
    if(child > 0)
    {
        parent = _parentOf(child);
        if(heapData[child] > heapData[parent])
        {
            temp = heapData[parent];
            heapData[parent] = heapData[child];
            heapData[child] = temp;
            _siftUp(child);
        }
    }
}

递归调用应为_siftUp(parent),否则您永远不会将任何项目筛选到多个级别。

答案 1 :(得分:1)

你的删除方法很好,而你的_siftDown有问题。 你和你的左孩子一起倒下并不总是正确的。

void Heap<TYPE>::_siftDown(int parent)
{
    TYPE temp;
    int left= _leftChildOf(parent);
    int right= _rightChildOf(parent);
    int max= parent;
    if(left< currSize && heapData[left] > heapData[max])
    {
        max= left;
    }
    if(right< currSize && heapData[right] > heapData[max])
    {
        max= right;
    }
    if( max!=parent ) //need to sift down
    {
        temp = heapData[max];
        heapData[max] = heapData[parent];
        heapData[parent] = temp;
        _siftDown(max);
    }
}

}

答案 2 :(得分:0)

您可以使用以下函数而不是实现自己的堆:

std::make_heap
std::push_heap
std::pop_heap

您可以在算法标题中找到它们

答案 3 :(得分:0)

heapData[0] = heapData[currSize];

在这里你不应该使用heapData[currSize],否则你将堆的最后一个元素复制到顶部。

例如,从堆5中删除currSize3并执行

heapData[0] = heapData[3];

将在10创建heapData[0]的副本。

答案 4 :(得分:-1)

无需仔细查看代码 你意识到测试从未被初始化?

int test; //initialization should happen here
while(inlist.remove(test))
    cout << test << endl;

我也不明白Heap :: remove(dataOut)参数的用途是什么。它与Heap :: remove(void)不同吗?