首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >我是否正确地实现了"Heapify“算法?

我是否正确地实现了"Heapify“算法?
EN

Stack Overflow用户
提问于 2011-11-15 08:42:34
回答 2查看 30.7K关注 0票数 18

我正在为一个计算机科学类创建一个堆实现,我想知道下面的递归函数是否会从一个还不是堆的数组对象中创建一个堆。代码如下:

void Heap::Heapify(int i)
{
    int temp, l, r, heapify;
    l = LeftChild(i);// get the left child
    r = RightChild(i);// get the right child

    //if one of the children is bigger than the index
    if((Data[i] < Data[l]) || (Data[i]< Data[r]))
    {
        //if left is the bigger child
        if(Data[l] > Data[r])
        {
            //swap parent with left child
            temp = Data[i];
            Data[i] = Data[l];
            Data[l] = temp;
            heapify = l; // index that was swapped
        }
        //if right is the bigger child
        else
        {
            //swap parent with right child
            temp = Data[i];
            Data[i] = Data[r];
            Data[r] = temp;
            heapify = r; // index that was swapped
        }
        // do a recursive call with the index
        //that was swapped
        Heapify(heapify);
    }
}

其想法是,您可以查看给定索引处的数据是否大于它的所有子项。如果是,则函数结束时不会出现问题。否则,它会检查哪个最大(左或右子对象),然后将其与索引互换。然后在交换发生的索引处调用heapify。

根据ildjarn的要求,我包含了完整的类定义和实现文件,以帮助回答我的问题:

这是头文件:

#ifndef HEAP_H
#define HEAP_H
//Programmer: Christopher De Bow
//Date: november 15, 2011

class Heap
{ 
private:
    int Data [100];
    int Parent(int);
    int RightChild(int);
    int LeftChild(int);
    void Heapify(int);
    void BuildHeap();

public:
    Heap();
    void insert();
    void HeapSort();
    void ExtractMaximum();
    int Maximum();
    void PrintHeap();
    int heapsize;
    void SetData(int[]);
};

#endif

和实现文件:

#include <iostream>
#include "Heap.h"
using namespace std;
//Programmer: Christopher De Bow
//Date: november 15, 2011

Heap::Heap()
{
    int init [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    heapsize = 10;
    SetData(init);
}

int Heap::Parent(int index)
{
    int Rval;
    if(index%2 == 0)// if the index is even
    {
        Rval = ((index-1)/2);
    }
    else// if the index is odd
    {
        Rval = (index/2);
    }
    return Rval;
}

int Heap::RightChild(int arrplace)
{
    int ret;
    ret = ((2*arrplace)+2); //rightchild is index times 2 plus 2
    return ret;
}

int Heap::LeftChild(int i)
{
    int rval;
    rval = ((2*i)+1); //leftchild is index times 2 plus 1
    return rval;
}

void Heap::Heapify(int i)
{
    int temp, l, r, heapify;

    l = LeftChild(i); // get the left child
    r = RightChild(i); // get the right child

    if((l <= heapSize) && (data[l] > data[i]))
    {
        heapify = l;
    {
    else
    {
        heapfiy = i;
    }
    if((r <= heapSize) && (data[r] > data[heapify]))
    {
        heapify = r;
    }
    if(heapify != i) // one of the two child nodes has proved
    {                // larger than Data[i], so interchange values
        //swap parent with left child
        temp = Data[i];
        Data[i] = Data[heapify];
        Data[heapify] = temp;
        Heapify(heapify);
    }
}

void Heap::BuildHeap()
{
    // we do not have a heap
    // we will make a heap
    // by calling heapify starting at the lowest
    // internal node in the heap
    for(int i = heapsize; i >= 1; i--)
    {
        Heapify(i-1);
    }
}

void Heap::insert()
{
    int insert;
    heapsize = (heapsize + 1);
    //getting data from the user
    cout<<"what data would you like to insert?"<<endl;
    cin>>insert;
    Data[heapsize] = insert;
    BuildHeap(); //call BuildHeap on array
    cout<<"done"<<endl;
}

void Heap::PrintHeap()
{
    BuildHeap();
    for(int count = 0; count < (heapsize-1); count++)
    {
        cout<<Data[count];// print out every element in heap
    }
    cout<<endl<<endl;
}

void Heap::HeapSort()
{
    BuildHeap();
    int temp;
    // do this for every elem in heap:
    for(int i = 0; i < heapsize; i++)
    {
        temp = Data[heapsize-1];
        Data[heapsize-1] = Data[0];
        Data[0] = temp;
        heapsize--;
        BuildHeap();
    }
    PrintHeap();
}

void Heap::ExtractMaximum()
{
    BuildHeap();
    //assign last thing in heap to first thing in heap
    Data[0] = Data[heapsize];
    heapsize --; // decrease heapsize by one
    Heapify(0); // heapify from the top
}

int Heap::Maximum()
{
    int Rval;
    BuildHeap();// make sure we have a heap
    Rval = Data[0];
    return Rval; // return top thing
}

//initialize the elements in the "Data" array
void Heap::SetData(int x[])
{
    for(int i = 0; i <= (heapsize); i++)
    {
        Data[i] = x[i]; 
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-11-15 18:48:33

你的算法起作用了。问题出在算法到代码的转换上。假设您将数据声明为:

int Data[7];

然后用初始值{0, 1, 2, 3, 4, 5, 6}填充它。假设LeftChild(i)RightChild(i)的定义如下:

#define LeftChild(i) ((i << 1) + 1)
#define RightChild(i) ((i << 1) + 2)

然后是你的函数BuildHeap(),它应该是这样的:

void Heap::BuildHeap()
{
    for(int i = (7 >> 1); i >= 1; i--) // in general, replace 7 with 
                                       // (sizeof(Data)/sizeof(int)), presuming 
                                       // you have an array of int's. if not, 
                                       // replace int with the relevant data type
    Heapify(i-1);
}

将在最右下角的子树根上开始Heapify进程。在本例中,这是数组索引2,左子数组为5,右子数组为6。Heapify将正确地交换2和6,并递归调用Heapify(6)

在这里,整个船都会搁浅!目前,你的树看起来像:

                         0
                    1         2
                 3     4   5     6
            u n d e f i n e d  s p a c e

因此,调用Heapify(6)会尽职尽责地将Data[6]的值与Data[13]Data[14]进行比较( C++的危险之处在于它没有强制执行数组边界,这与Java不同)。显然,后两个值可以是任何留在RAM中的垃圾。这里的一个解决方案,丑陋但有效的补丁,是在数据声明中添加8个元素,并将它们都初始化为比数组中任何元素都低的值。更好的解决方案是向您的类添加一个heapSize变量,并将其设置为等于数组的长度:

heapSize = (sizeof(Data)/sizeof(int));

然后集成逻辑,仅在子节点是树的有效叶子时对其进行比较。一种有效的实现方式是:

void Heap::Heapify(int i)
{
    int temp, l, r, heapify;

    l = LeftChild(i); // get the left child
    r = RightChild(i); // get the right child

    if((l <= heapSize) && (Data[l] > Data[i]))
        heapify = l;
    else heapfiy = i;
    if((r <= heapSize) && (Data[r] > Data[heapify]))
        heapify = r;
    if(heapify != i) // one of the two child nodes has proved 
                     // larger than Data[i], so interchange values
    {
        //swap parent with left child
        temp = Data[i];
        Data[i] = Data[heapify];
        Data[heapify] = temp;

        Heapify(heapify);
    }
}

因此,总而言之,解决方案就像添加逻辑一样简单,以确保子节点是树的有效叶子,并且您的main函数将具有以下内容:

Heap heap;

// initialize Data here    

heap.BuildHeap();

希望这能有所帮助。

票数 9
EN

Stack Overflow用户

发布于 2011-11-15 09:29:55

不是的。在树上

      1
     / \
    /   \
   /     \
  2       3
 / \     / \
6   7   4   5

输出结果将是

      3
     / \
    /   \
   /     \
  2       5
 / \     / \
6   7   4   1

它有几个堆冲突。(我假设如果相应的子级不存在,Data[l]Data[r]就是负无穷大。您可能需要额外的逻辑来确保这一点。)

您的函数所做的是修复一棵树,该树可能不是堆,但其左子树和右子树都是堆。您需要在每个节点上以后序调用它(即,对于i,从n-1到0),以便在调用Heapify(i)时,i的子节点是堆。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8130177

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档