我正在为一个计算机科学类创建一个堆实现,我想知道下面的递归函数是否会从一个还不是堆的数组对象中创建一个堆。代码如下:
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];
}
}
发布于 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();
希望这能有所帮助。
发布于 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的子节点是堆。
https://stackoverflow.com/questions/8130177
复制相似问题