OSHeap实际上是一个完全二叉树,再插入和删除的时候都进行了排序。
#include "OSHeap.h"
#include <ctime>
#include <cstdlib>
int main(int argc, char * argv[])
{
srand(unsigned(time(0)));
cout << "===============insert value==============" << endl;
OSHeap osHeap;
for (int i =0 ;i < 10 ;i ++)
{
OSHeapElem *pElem = new OSHeapElem();
int value = rand()%100;
pElem->SetValue(value);
cout << "insert value:" << value << endl;
osHeap.Insert(pElem);
}
cout << "===============Extract min value==============" << endl;
OSHeapElem *pElem = NULL;
while((pElem = osHeap.ExtractMin()) != NULL)
{
cout << "min value:" << pElem->GetValue() << endl;
}
return 0;
}
#ifndef _OSHEAP_H_
#define _OSHEAP_H_
#define _OSHEAP_TESTING_ 0
#include "OSCond.h"
class OSHeapElem;
class OSHeap
{
public:
enum
{
kDefaultStartSize = 1024 //UInt32
};
//设置堆的初始大小,如果元素超过指定大小,则会自动增加内存,堆内部采用数组实现
OSHeap(UInt32 inStartSize = kDefaultStartSize);
~OSHeap() { if (fHeap != NULL) delete fHeap; }
//ACCESSORS
UInt32 CurrentHeapSize() { return fFreeIndex - 1; }
//查看最小元素值
OSHeapElem* PeekMin() { if (CurrentHeapSize() > 0) return fHeap[1]; return NULL; }
//MODIFIERS
//These are the two primary operations supported by the heap
//abstract data type. both run in log(n) time.
//插入一个元素
void Insert(OSHeapElem* inElem);
//取出最小的元素
OSHeapElem* ExtractMin() { return Extract(1); }
//removes specified element from the heap
OSHeapElem* Remove(OSHeapElem* elem);
#if _OSHEAP_TESTING_
//returns true if it passed the test, false otherwise
static Bool16 Test();
#endif
private:
OSHeapElem* Extract(UInt32 index);
#if _OSHEAP_TESTING_
//verifies that the heap is in fact a heap
void SanityCheck(UInt32 root);
#endif
OSHeapElem** fHeap;
UInt32 fFreeIndex;
UInt32 fArraySize;
};
class OSHeapElem
{
public:
OSHeapElem(void* enclosingObject = NULL)
: fValue(0), fEnclosingObject(enclosingObject), fCurrentHeap(NULL) {}
~OSHeapElem() {}
//This data structure emphasizes performance over extensibility
//If it were properly object-oriented, the compare routine would
//be virtual. However, to avoid the use of v-functions in this data
//structure, I am assuming that the objects are compared using a 64 bit number.
//
void SetValue(SInt64 newValue) { fValue = newValue; }
SInt64 GetValue() { return fValue; }
void* GetEnclosingObject() { return fEnclosingObject; }
void SetEnclosingObject(void* obj) { fEnclosingObject = obj; }
Bool16 IsMemberOfAnyHeap() { return fCurrentHeap != NULL; }
private:
SInt64 fValue;
void* fEnclosingObject;
OSHeap* fCurrentHeap;
friend class OSHeap;
};
#endif //_OSHEAP_H_
#include "OSHeap.h"
#include "OSMemory.h"
OSHeap::OSHeap(UInt32 inStartSize)
: fFreeIndex(1)
{
if (inStartSize < 2)
fArraySize = 2;
else
fArraySize = inStartSize;
fHeap = NEW OSHeapElem*[fArraySize];
}
void OSHeap::Insert(OSHeapElem* inElem)
{
Assert(inElem != NULL);
if ((fHeap == NULL) || (fFreeIndex == fArraySize))
{
fArraySize *= 2;
OSHeapElem** tempArray = NEW OSHeapElem*[fArraySize];
if ((fHeap != NULL) && (fFreeIndex > 1))
memcpy(tempArray, fHeap, sizeof(OSHeapElem*) * fFreeIndex);
delete [] fHeap;
fHeap = tempArray;
}
Assert(fHeap != NULL);
Assert(inElem->fCurrentHeap == NULL);
Assert(fArraySize > fFreeIndex);
#if _OSHEAP_TESTING_
SanityCheck(1);
#endif
//insert the element into the last leaf of the tree
fHeap[fFreeIndex] = inElem;
//bubble the new element up to its proper place in the heap
//start at the last leaf of the tree
UInt32 swapPos = fFreeIndex;
while (swapPos > 1)
{
//move up the chain until we get to the root, bubbling this new element
//to its proper place in the tree
UInt32 nextSwapPos = swapPos >> 1;
//if this child is greater than it's parent, we need to do the old
//switcheroo
if (fHeap[swapPos]->fValue < fHeap[nextSwapPos]->fValue)
{
OSHeapElem* temp = fHeap[swapPos];
fHeap[swapPos] = fHeap[nextSwapPos];
fHeap[nextSwapPos] = temp;
swapPos = nextSwapPos;
}
else
//if not, we are done!
break;
}
inElem->fCurrentHeap = this;
fFreeIndex++;
}
OSHeapElem* OSHeap::Extract(UInt32 inIndex)
{
if ((fHeap == NULL) || (fFreeIndex <= inIndex))
return NULL;
#if _OSHEAP_TESTING_
SanityCheck(1);
#endif
//store a reference to the element we want to extract
OSHeapElem* victim = fHeap[inIndex];
Assert(victim->fCurrentHeap == this);
victim->fCurrentHeap = NULL;
//but now we need to preserve this heuristic. We do this by taking
//the last leaf, putting it at the empty position, then heapifying that chain
fHeap[inIndex] = fHeap[fFreeIndex - 1];
fFreeIndex--;
//The following is an implementation of the Heapify algorithm (CLR 7.1 pp 143)
//The gist is that this new item at the top of the heap needs to be bubbled down
//until it is bigger than its two children, therefore maintaining the heap property.
UInt32 parent = inIndex;
while (parent < fFreeIndex)
{
//which is bigger? parent or left child?
UInt32 greatest = parent;
UInt32 leftChild = parent * 2;
if ((leftChild < fFreeIndex) && (fHeap[leftChild]->fValue < fHeap[parent]->fValue))
greatest = leftChild;
//which is bigger? the biggest so far or the right child?
UInt32 rightChild = (parent * 2) + 1;
if ((rightChild < fFreeIndex) && (fHeap[rightChild]->fValue < fHeap[greatest]->fValue))
greatest = rightChild;
//if the parent is in fact bigger than its two children, we have bubbled
//this element down far enough
if (greatest == parent)
break;
//parent is not bigger than at least one of its two children, so swap the parent
//with the largest item.
OSHeapElem* temp = fHeap[parent];
fHeap[parent] = fHeap[greatest];
fHeap[greatest] = temp;
//now heapify the remaining chain
parent = greatest;
}
return victim;
}
OSHeapElem* OSHeap::Remove(OSHeapElem* elem)
{
if ((fHeap == NULL) || (fFreeIndex == 1))
return NULL;
#if _OSHEAP_TESTING_
SanityCheck(1);
#endif
//first attempt to locate this element in the heap
UInt32 theIndex = 1;
for ( ; theIndex < fFreeIndex; theIndex++)
if (elem == fHeap[theIndex])
break;
//either we've found it, or this is a bogus element
if (theIndex == fFreeIndex)
return NULL;
return Extract(theIndex);
}
#if _OSHEAP_TESTING_
void OSHeap::SanityCheck(UInt32 root)
{
//make sure root is greater than both its children. Do so recursively
if (root < fFreeIndex)
{
if ((root * 2) < fFreeIndex)
{
Assert(fHeap[root]->fValue <= fHeap[root * 2]->fValue);
SanityCheck(root * 2);
}
if (((root * 2) + 1) < fFreeIndex)
{
Assert(fHeap[root]->fValue <= fHeap[(root * 2) + 1]->fValue);
SanityCheck((root * 2) + 1);
}
}
}
Bool16 OSHeap::Test()
{
OSHeap victim(2);
OSHeapElem elem1;
OSHeapElem elem2;
OSHeapElem elem3;
OSHeapElem elem4;
OSHeapElem elem5;
OSHeapElem elem6;
OSHeapElem elem7;
OSHeapElem elem8;
OSHeapElem elem9;
OSHeapElem* max = victim.ExtractMin();
if (max != NULL)
return false;
elem1.SetValue(100);
victim.Insert(&elem1);
max = victim.ExtractMin();
if (max != &elem1)
return false;
max = victim.ExtractMin();
if (max != NULL)
return false;
elem1.SetValue(100);
elem2.SetValue(80);
victim.Insert(&elem1);
victim.Insert(&elem2);
max = victim.ExtractMin();
if (max != &elem2)
return false;
max = victim.ExtractMin();
if (max != &elem1)
return false;
max = victim.ExtractMin();
if (max != NULL)
return false;
victim.Insert(&elem2);
victim.Insert(&elem1);
max = victim.ExtractMin();
if (max != &elem2)
return false;
max = victim.ExtractMin();
if (max != &elem1)
return false;
elem3.SetValue(70);
elem4.SetValue(60);
victim.Insert(&elem3);
victim.Insert(&elem1);
victim.Insert(&elem2);
victim.Insert(&elem4);
max = victim.ExtractMin();
if (max != &elem4)
return false;
max = victim.ExtractMin();
if (max != &elem3)
return false;
max = victim.ExtractMin();
if (max != &elem2)
return false;
max = victim.ExtractMin();
if (max != &elem1)
return false;
elem5.SetValue(50);
elem6.SetValue(40);
elem7.SetValue(30);
elem8.SetValue(20);
elem9.SetValue(10);
victim.Insert(&elem5);
victim.Insert(&elem3);
victim.Insert(&elem1);
max = victim.ExtractMin();
if (max != &elem5)
return false;
victim.Insert(&elem4);
victim.Insert(&elem2);
max = victim.ExtractMin();
if (max != &elem4)
return false;
max = victim.ExtractMin();
if (max != &elem3)
return false;
victim.Insert(&elem2);
max = victim.ExtractMin();
if (max != &elem2)
return false;
victim.Insert(&elem2);
victim.Insert(&elem6);
max = victim.ExtractMin();
if (max != &elem6)
return false;
victim.Insert(&elem6);
victim.Insert(&elem3);
victim.Insert(&elem4);
victim.Insert(&elem5);
max = victim.ExtractMin();
if (max != &elem6)
return false;
max = victim.ExtractMin();
if (max != &elem5)
return false;
victim.Insert(&elem8);
max = victim.ExtractMin();
if (max != &elem8)
return false;
max = victim.ExtractMin();
if (max != &elem4)
return false;
victim.Insert(&elem5);
victim.Insert(&elem4);
victim.Insert(&elem9);
victim.Insert(&elem7);
victim.Insert(&elem8);
victim.Insert(&elem6);
max = victim.ExtractMin();
if (max != &elem9)
return false;
max = victim.ExtractMin();
if (max != &elem8)
return false;
max = victim.ExtractMin();
if (max != &elem7)
return false;
max = victim.ExtractMin();
if (max != &elem6)
return false;
max = victim.ExtractMin();
if (max != &elem5)
return false;
max = victim.ExtractMin();
if (max != &elem4)
return false;
max = victim.ExtractMin();
if (max != &elem3)
return false;
max = victim.ExtractMin();
if (max != &elem2)
return false;
max = victim.ExtractMin();
if (max != &elem2)
return false;
max = victim.ExtractMin();
if (max != &elem1)
return false;
max = victim.ExtractMin();
if (max != NULL)
return false;
victim.Insert(&elem1);
victim.Insert(&elem2);
victim.Insert(&elem3);
victim.Insert(&elem4);
victim.Insert(&elem5);
victim.Insert(&elem6);
victim.Insert(&elem7);
victim.Insert(&elem8);
victim.Insert(&elem9);
max = victim.Remove(&elem7);
if (max != &elem7)
return false;
max = victim.Remove(&elem9);
if (max != &elem9)
return false;
max = victim.ExtractMin();
if (max != &elem8)
return false;
max = victim.Remove(&elem2);
if (max != &elem2)
return false;
max = victim.Remove(&elem2);
if (max != NULL)
return false;
max = victim.Remove(&elem8);
if (max != NULL)
return false;
max = victim.Remove(&elem5);
if (max != &elem5)
return false;
max = victim.Remove(&elem6);
if (max != &elem6)
return false;
max = victim.Remove(&elem1);
if (max != &elem1)
return false;
max = victim.ExtractMin();
if (max != &elem4)
return false;
max = victim.Remove(&elem1);
if (max != NULL)
return false;
return true;
}
#endif