You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
4.8 KiB
199 lines
4.8 KiB
3 years ago
|
//
|
||
|
// HtHeap.cc
|
||
|
//
|
||
|
// HtHeap: A Heap class which holds objects of type Object.
|
||
|
// (A heap is a semi-ordered tree-like structure.
|
||
|
// it ensures that the first item is *always* the largest.
|
||
|
// NOTE: To use a heap, you must implement the Compare() function for
|
||
|
// your Object classes. The assumption used here is -1 means
|
||
|
// less-than, 0 means equal, and +1 means greater-than. Thus
|
||
|
// this is a "min heap" for that definition.)
|
||
|
//
|
||
|
// Part of the ht://Dig package <http://www.htdig.org/>
|
||
|
// Copyright (c) 1999-2004 The ht://Dig Group
|
||
|
// For copyright details, see the file COPYING in your distribution
|
||
|
// or the GNU Library General Public License (LGPL) version 2 or later
|
||
|
// <http://www.gnu.org/copyleft/lgpl.html>
|
||
|
//
|
||
|
// $Id: HtHeap.cc,v 1.12 2004/05/28 13:15:20 lha Exp $
|
||
|
//
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "htconfig.h"
|
||
|
#endif /* HAVE_CONFIG_H */
|
||
|
|
||
|
#include "HtHeap.h"
|
||
|
|
||
|
#ifdef HAVE_STD
|
||
|
#include <fstream>
|
||
|
#ifdef HAVE_NAMESPACES
|
||
|
using namespace std;
|
||
|
#endif
|
||
|
#else
|
||
|
#include <fstream.h>
|
||
|
#endif /* HAVE_STD */
|
||
|
|
||
|
//*********************************************************************
|
||
|
// void HtHeap::HtHeap()
|
||
|
// Default constructor
|
||
|
//
|
||
|
HtHeap::HtHeap()
|
||
|
{
|
||
|
data = new HtVector;
|
||
|
}
|
||
|
|
||
|
|
||
|
//*********************************************************************
|
||
|
// void HtHeap::HtHeap(HtVector vector)
|
||
|
// Constructor from vector
|
||
|
// (has the side effect of not allocating double memory)
|
||
|
//
|
||
|
HtHeap::HtHeap(HtVector vector)
|
||
|
{
|
||
|
int size = vector.Count();
|
||
|
data = static_cast<HtVector*>(vector.Copy());
|
||
|
|
||
|
// Now we have to "heapify" -- start at the first interior node
|
||
|
// And push each node down into its subtree
|
||
|
// (This is O(n)!)
|
||
|
for (int i = parentOf(size); i >= 0; i--)
|
||
|
pushDownRoot(i);
|
||
|
}
|
||
|
|
||
|
|
||
|
//*********************************************************************
|
||
|
// void HtHeap::~HtHeap()
|
||
|
// Destructor
|
||
|
//
|
||
|
HtHeap::~HtHeap()
|
||
|
{
|
||
|
Destroy();
|
||
|
}
|
||
|
|
||
|
|
||
|
//*********************************************************************
|
||
|
// void HtHeap::Destroy()
|
||
|
// Deletes all objects from the heap
|
||
|
//
|
||
|
void HtHeap::Destroy()
|
||
|
{
|
||
|
data->Destroy();
|
||
|
delete data;
|
||
|
}
|
||
|
|
||
|
|
||
|
//*********************************************************************
|
||
|
// void HtHeap::Add(Object *object)
|
||
|
// Add an object to the heap.
|
||
|
//
|
||
|
void HtHeap::Add(Object *object)
|
||
|
{
|
||
|
data->Add(object);
|
||
|
percolateUp(data->Count() - 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//*********************************************************************
|
||
|
// Object *HtHeap::Remove()
|
||
|
// Remove an object from the top of the heap
|
||
|
// This requires re-heapifying by placing the last element on the top
|
||
|
// and pushing it down.
|
||
|
//
|
||
|
Object *HtHeap::Remove()
|
||
|
{
|
||
|
Object *min = Peek();
|
||
|
|
||
|
data->Assign(data->Last(), 0);
|
||
|
data->RemoveFrom(data->Count()-1);
|
||
|
|
||
|
if (data->Count() > 1)
|
||
|
pushDownRoot(0);
|
||
|
|
||
|
return min;
|
||
|
}
|
||
|
|
||
|
//*********************************************************************
|
||
|
// HtHeap *HtHeap::Copy() const
|
||
|
// Return a deep copy of the heap.
|
||
|
//
|
||
|
Object *HtHeap::Copy() const
|
||
|
{
|
||
|
HtHeap *heap = new HtHeap(*data);
|
||
|
|
||
|
return heap;
|
||
|
}
|
||
|
|
||
|
|
||
|
//*********************************************************************
|
||
|
// HtHeap &HtHeap::operator=(HtHeap &heap)
|
||
|
// Return a deep copy of the heap.
|
||
|
//
|
||
|
HtHeap &HtHeap::operator=(HtHeap &heap)
|
||
|
{
|
||
|
Destroy();
|
||
|
data = heap.data;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
//*********************************************************************
|
||
|
// voide HtHeap::percolateUp(int leaf)
|
||
|
// Pushes the node pointed to by leaf upwards
|
||
|
// it will travel as far as possible upwards to ensure the data is a heap
|
||
|
//
|
||
|
void HtHeap:: percolateUp(int leaf)
|
||
|
{
|
||
|
int parent = parentOf(leaf);
|
||
|
Object *value = data->Nth(leaf);
|
||
|
while (leaf > 0 &&
|
||
|
(value->compare(*(data->Nth(parent))) < 0))
|
||
|
{
|
||
|
data->Assign(data->Nth(parent), leaf);
|
||
|
leaf = parent;
|
||
|
parent = parentOf(leaf);
|
||
|
}
|
||
|
data->Assign(value, leaf);
|
||
|
}
|
||
|
|
||
|
//*********************************************************************
|
||
|
// void HtHeap::pushDownRoot(int root)
|
||
|
// Pushes the node pointed to by root into the heap
|
||
|
// it will go down as far as necessary to ensure the data is a heap
|
||
|
//
|
||
|
void HtHeap::pushDownRoot(int root)
|
||
|
{
|
||
|
int size = data->Count() - 1;
|
||
|
Object *value = data->Nth(root);
|
||
|
while (root < size)
|
||
|
{
|
||
|
int childPos = leftChildOf(root);
|
||
|
if (childPos < size)
|
||
|
{
|
||
|
if ( rightChildOf(root) < size &&
|
||
|
data->Nth(childPos + 1)->compare(*(data->Nth(childPos))) < 0 )
|
||
|
{
|
||
|
childPos++;
|
||
|
}
|
||
|
if ( data->Nth(childPos)->compare(*value) < 0 ) // -1, so smaller
|
||
|
{
|
||
|
// We have to swap this node with the root and then loop
|
||
|
data->Assign(data->Nth(childPos), root);
|
||
|
data->Assign(value, childPos);
|
||
|
root = childPos;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Found the right position, so we're done
|
||
|
data->Assign(value, root);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else // childPos >= heapSize
|
||
|
{
|
||
|
// At a leaf, so we're done
|
||
|
data->Assign(value, root);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|