一些堆类结构的实现代码。。。
//Heap.h
#ifndef HEAP_H
#define HEAP_H
#include <iostream>
#include <iomanip>
using namespace std;
#include "Queue.h"
#include "Stack.h"
#include "HeapExceptions.h"
template <class T>
/*
\brief: Heap built in an array,
using array to simulate the heap.
\mention: You can try another version
(class BinaryHeap) of heap implemented
by a specialized binary tree.
*/
class Heap
{
template <class T>
friend ostream &operator<<(ostream &, const Heap<T> &);
public:
Heap(T *, const int);
Heap(const Heap &);
~Heap();
int parent(int i) { return (i - 1) / 2; }
int left(int i) { return 2 * i + 1; }
int right(int i) { return (i + 1) * 2; }
T *list;
//length of array
int length;
//size of heap
int heapSize;
};
template <class T>
/*
/brief: A max heap built in an array.
from base class Heap.
*/
class MaxHeap : public Heap<T>
{
template <class T>
friend void heap_sort(T *, const int);
public:
MaxHeap(T *, const int);
void maxHeapify(int = 0);
void buildMaxHeap();
void push(const T &);
void pop();
};
/*
/brief: A min heap built in an array.
from base class Heap.
*/
template <class T>
class MinHeap : public Heap<T>
{
template <class T>
friend void heap_sort(int, T *, const int);
public:
MinHeap(T *, const int);
void minHeapify(int = 0);
void buildMinHeap();
void push(const T &);
void pop();
};
/*--------------Heap-----------------*/
template <class T>
Heap<T>::Heap(T *src, const int size)
: length(size), heapSize(size){
list = new T[size];
for (int i = 0; i < size; i++){
list[i] = src[i];
}
}
template <class T>
Heap<T>::Heap(const Heap<T> &src_heap){
length = src_heap.length;
heapSize = src_heap.heapSize;
list = new T[heapSize];
for (int i = 0; i < heapSize; i++){
list[i] = src_heap.list[i];
}
}
template <class T>
Heap<T>::~Heap(){
if (!list){
delete list;
}
}
template <class T>
ostream &operator<<(ostream &out, const Heap<T> &heap){
int i = 0;
int j = 1;
for (; i + j <= heap.heapSize; i += j, j *= 2){
for (int k = i; k < i + j; k++){
out << setw(4) << left << heap.list[k];
}
out << endl;
}
for (; i < heap.heapSize; i++){
cout << setw(4) << left << heap.list[i];
}
out << endl;
return out;
}
/*--------------MaxHeap-----------------*/
template <class T>
MaxHeap<T>::MaxHeap(T *src, const int size)
: Heap<T>(src, size){
buildMaxHeap();
}
template <class T>
void MaxHeap<T>::buildMaxHeap(){
for (int i = heapSize / 2 - 1; i >= 0; i--){
maxHeapify(i);
}
}
template <class T>
void MaxHeap<T>::maxHeapify(int i){
int largest = i;
if (right(i) < heapSize &&
list[largest] < list[right(i)]){
largest = right(i);
}
if (left(i) < heapSize &&
list[largest] < list[left(i)]){
largest = left(i);
}
swap(list + i, list + largest);
if (largest != i){
maxHeapify(largest);
}
}
template <class T>
void MaxHeap<T>::push(const T &k){
//if full, double the storage space
if (heapSize == length){
T *buffer = new T[heapSize];
for (int i = 0; i < heapSize; i++){
buffer[i] = list[i];
}
list = new T[length *= 2];
for (int i = 0; i < heapSize; i++){
list[i] = buffer[i];
}
}
//insert k
list[heapSize++] = k;
//maintain max heap property
int j = heapSize - 1;
while (j > 0 && list[parent(j)] < k){
swap(list + j, list + parent(j));
j = parent(j);
}
}
template <class T>
void MaxHeap<T>::pop(){
swap(list, list + heapSize - 1);
heapSize--;
maxHeapify(0);
}
template <class T>
void heap_sort(T *list, const int size){
//coupling
MaxHeap<T> heap(NULL, 0);
heap.list = list;
heap.length = heap.heapSize = size;
heap.buildMaxHeap();
for (int i = size - 1; i >= 1; i--){
swap(list, list + i);
heap.heapSize--;
heap.maxHeapify(0);
}
//decoupling
heap.list = NULL;
heap.length = heap.heapSize = 0;
}
/*--------------MinHeap-----------------*/
template <class T>
MinHeap<T>::MinHeap(T *list, const int size)
: Heap<T>(list, size){
buildMinHeap();
}
template <class T>
void MinHeap<T>::buildMinHeap(){
for (int i = heapSize / 2 - 1; i >= 0; i--){
minHeapify(i);
}
}
template <class T>
void MinHeap<T>::minHeapify(int i){
int least = i;
if (left(i) < heapSize &&
list[left(i)] < list[least]){
least = left(i);
}
if (right(i) < heapSize &&
list[right(i)] < list[least]){
least = right(i);
}
swap(list + i, list + least);
if (least != i){
minHeapify(least);
}
}
template <class T>
void MinHeap<T>::push(const T &k){
//if full, double the storage space
if (heapSize == length){
T *buffer = new T[heapSize];
for (int i = 0; i < heapSize; i++){
buffer[i] = list[i];
}
list = new T[length *= 2];
for (int i = 0; i < heapSize; i++){
list[i] = buffer[i];
}
}
//insert k
list[heapSize++] = k;
//maintain max heap property
int j = heapSize - 1;
while (j > 0 && list[parent(j)] > k){
swap(list + j, list + parent(j));
j = parent(j);
}
}
template <class T>
void MinHeap<T>::pop(){
swap(list, list + heapSize - 1);
heapSize--;
minHeapify(0);
}
template <class T>
void heap_sort(int m, T *list, const int size){
//coupling
MinHeap<T> heap(NULL, 0);
heap.list = list;
heap.length = heap.heapSize = size;
heap.buildMinHeap();
for (int i = size - 1; i >= 1; i--){
heap.minHeapify(0);
swap(heap.list, heap.list + i);
heap.heapSize--;
}
//decoupling
heap.length = heap.heapSize = 0;
heap.list = NULL;
}
//utility function
template <class T>
void swap(T *p_1, T *p_2){
T temp = *p_1;
*p_1 = *p_2;
*p_2 = temp;
}
template <class T>
/*
\brief: Node for height-biased leftist tree,
which has HBLT property: x.left.h >= x.right.h.
\detail: data mem @h : length of the shortest
simple path from this node to a leaf node.
*/
class HBLTNode
{
public:
HBLTNode(HBLTNode<T> *p_1 = NULL,
HBLTNode<T> *p_2 = NULL,
T k = T(), int s = 1)
: left(p_1), right(p_2), key(k), h(s) { }
HBLTNode<T> *left;
HBLTNode<T> *right;
T key;
int h;
};
template <class T>
class HBLTMaxHeap
{
template <class T>
friend HBLTNode<T> *meld(HBLTNode<T> **, HBLTNode<T> **);
template <class T>
friend void meld(HBLTNode<T> **, HBLTNode<T> **, int);
template <class T>
friend void leftUp(HBLTNode<T> **, HBLTNode<T> **);
template <class T>
friend void rightUp(HBLTNode<T> **, HBLTNode<T> **);
template <class T>
friend void linkCpy(HBLTNode<T> **, HBLTNode<T> **);
public:
HBLTMaxHeap(T *list, const int size);
~HBLTMaxHeap();
bool isEmpty() { return NULL == root; }
int size() { return length; }
HBLTNode<T> *top() { return root; }
void inorderTraverse();
void pop();
void push(const T &);
void meldTree(HBLTMaxHeap<T> &);
private:
void clearSubtree(HBLTNode<T> *);
void output(HBLTNode<T> *);
HBLTNode<T> *root;
int length;
};
//#define USE_ITERATE 0
template <class T>
/*
\mention:
1. There are two ways to initialize a
HBLTMaxHeap, use #define USE_ITERATE
to choose the iterative onstructor,
otherwise the class will choose the
default recursive constructor.
2. Different constructors could build
different heaps, even though they
have the same parameters.
*/
HBLTMaxHeap<T>::HBLTMaxHeap(T *list, const int size)
: length(size){
#ifndef USE_ITERATE //using recursive initialization
HBLTNode<T> **nodes = new HBLTNode<T> *[size];
for (int i = 0; i < size; i++){
nodes[i] = new HBLTNode<T>;
nodes[i]->key = list[i];
}
for (int k = 2; k < size; k *= 2){
for (int i = 0; i < size - 1; i += k){
nodes[i] = meld(&(nodes[i]), &(nodes[i + k / 2]));
}
if (size % k >= k / 2){
int m = size - size % k;
nodes[m - k] = meld(&(nodes[m - k]), &(nodes[m]));
}
}
root = nodes[0];
#else //using iterative initialization
ArrayQueue<HBLTNode<T> *> q(size);
//initialize and load nodes
for (int i = 0; i < size; i++){
HBLTNode<T> *node = new HBLTNode<T>(NULL, NULL, list[i]);
HBLTNode<T> *&ptr = node;
q.push(ptr);
}
for (int i = 0; i < size - 1; i++){
HBLTNode<T> *r_1 =
(q.isEmpty()) ? NULL : q.front();
q.pop();
HBLTNode<T> *r_2 =
(q.isEmpty()) ? NULL : q.front();
q.pop();
HBLTNode<T> *node = meld<T>(0, &r_1, &r_2);
HBLTNode<T> *&ptr = node;
q.push(ptr);
}
root = q.front();
#endif
}
template <class T>
HBLTMaxHeap<T>::~HBLTMaxHeap(){
clearSubtree(root);
}
template <class T>
void HBLTMaxHeap<T>::inorderTraverse(){
output(root);
}
template <class T>
void HBLTMaxHeap<T>::output(HBLTNode<T> *cur){
if (cur){
output(cur->left);
cout << setw(4) << cur->key;
output(cur->right);
}
}
template <class T>
void HBLTMaxHeap<T>::clearSubtree(HBLTNode<T> *cur){
if (cur){
clearSubtree(cur->left);
clearSubtree(cur->right);
delete cur;
}
}
template <class T>
void HBLTMaxHeap<T>::pop(){
try{
if (isEmpty()){
throw NullHeapException();
}
}
catch (NullHeapException &exc){
cout << exc.what();
}
HBLTNode<T> *del = root;
root = meld<T>(&(root->left), &(root->right));
delete del;
}
template <class T>
void HBLTMaxHeap<T>::push(const T &k){
HBLTNode<T> *new_node = new HBLTNode<T>;
new_node->key = k;
root = meld<T>(&root, &new_node);
length++;
}
template <class T>
void HBLTMaxHeap<T>::meldTree(HBLTMaxHeap<T> &heap){
root = meld<T>(&root, &(heap.root));
length += heap.length;
heap.root = NULL;
heap.length = 0;
}
template <class T>
/*
\fn meld(HBLTNode<T> *r_1, HBLTNode<T> *r_2)
\return pointer to the root node of the
new tree.
\pre r_1 and r_2 are roots of two distinct trees.
\brief: merge two HBLT trees.
\param r_1 A max heap and also a HBLT tree to be merged.
\param r_2 The same as @param r_1.
\post two trees are merged together.
*/
HBLTNode<T> *meld(HBLTNode<T> **r_1, HBLTNode<T> **r_2){
//if one of two (sub)trees is empty,
//skip;
if (*r_1 == NULL){
*r_1 = *r_2;
return *r_1;
}
if (*r_2 == NULL){
return *r_1;
}
/*Maintain max heap property*/
//make sure that r_1->key >= r_2->key
if ((*r_1)->key < (*r_2)->key){
swap<HBLTNode<T> *>(r_1, r_2);
}
//recursive
(*r_1)->right = meld(&((*r_1)->right), r_2);
/*maintain HBLT property*/
if ((*r_1)->left != NULL){
if ((*r_1)->left->h < (*r_1)->right->h){
//fix HBLT property: left.h >= right.h
swap<HBLTNode<T> *>(&((*r_1)->left), &((*r_1)->right));
}
//update r_1->h
(*r_1)->h = (*r_1)->right->h + 1;
}
else{//left subtree of r_1 is empty
(*r_1)->left = (*r_1)->right;
(*r_1)->right = NULL;
(*r_1)->h = 1;
}
return *r_1;
}
template <class T>
/*
\fn meld(HBLTNode<T> **r_1, HBLTNode<T> **r_2, int = 0)
\return pointer to root node of the merged tree.
\pre r_1 and r_2 are roots of two distinct trees.
\brief A iterative version of function
meld(HBLTNode<T> **r_1, HBLTNode<T> **r_2).
\post two trees are merged together.
\mention When you want to use this iterative version,
remember to add a zero at the beginning of the
formal parameter list.
*/
HBLTNode<T> *meld(int m, HBLTNode<T> **r_1, HBLTNode<T> **r_2){
//stack to store all the points that 've been changed.
ArrayStack<HBLTNode<T> *> check_points;
if ((*r_1)->h < (*r_2)->h){
swap<HBLTNode<T> *>(r_1, r_2);
}
//temp: a parent node of two subtrees waiting to be merged.
HBLTNode<T> **temp = new HBLTNode<T> *;
*temp = new HBLTNode<T>((*r_1), (*r_2));
//p: parent node of temp
HBLTNode<T> **p = new HBLTNode<T> *;
while (*r_1 != NULL && *r_2 != NULL){
if ((*r_1)->h == (*r_2)->h &&
(*r_1)->key > (*r_2)->key){
(*temp)->left = *r_2;
(*temp)->right = *r_1;
swap<HBLTNode<T> *>(r_1, r_2);
}
if ((*r_1)->key <= (*r_2)->key){
*p = *r_2;
rightUp<T>(temp, p);
}
else{
*p = *r_1;
leftUp<T>(temp, p);
}
check_points.push(*p);
(*r_1) = (*temp)->left;
(*r_2) = (*temp)->right;
}
(*p)->right = ((*r_1) == NULL) ? (*r_2) : (*r_1);
//recover
HBLTNode<T> *res = NULL;
while (!check_points.isEmpty()){
res = check_points.top();
check_points.pop();
res->h = (res->right) ? res->right->h + 1 : 1;
}
delete (*temp);
delete temp;
delete p;
return res;
}
template <class T>
/*
\fn leftUp(HBLTNode<T> **down, HBLTNode<T> **up)
\brief: Exchange the position of a parent node and
a left child node.
\param down A left (child) node.
\param up A parent node whose left child is @param down.
*/
void leftUp(HBLTNode<T> **down, HBLTNode<T> **up){
HBLTNode<T> *r = (*down)->right;
linkCpy(down, up);
(*up)->left = *down;
(*up)->right = r;
}
template <class T>
/*
\fn rightUp(HBLTNode<T> **temp, HBLTNode<T> **p)
\brief: Exchange the position of a parent node and
a right child node.
\param down A right (child) node.
\param up A parent node whose right child is @param down.
*/
void rightUp(HBLTNode<T> **down, HBLTNode<T> **up){
HBLTNode<T> *r = (*down)->left;
linkCpy(down, up);
(*up)->left = r;
(*up)->right = *down;
}
template <class T>
void linkCpy(HBLTNode<T> **dest, HBLTNode<T> **src){
(*dest)->left = (*src)->left;
(*dest)->right = (*src)->right;
}
#endif