第一步,创建“堆”这个数据结构
#pragma once
#include<assert.h>
template <typename E, typename Comp>
class heap
{
private:
E* Heap; //Pointer to the heap array
int maxsize; //Maximum size of the heap
int n; //Number of elements now in the heap
//Helper function to put element in its correct place,and that moves the father node down
void siftdown(int pos);
public:
heap(E* h, int num, int max);
int size()const;
bool isLeaf(int pos)const;
int leftchild(int pos)const;
int rightchild(int pos)const;
int parent(int pos)const;
void buildHeap();
void insert(const E& it);
E removefirst();
E remove(int pos);
};
//Swap two elements in the container
template<typename E>
void swap(E* array, int pos1, int pos2) {
E temp = array[pos1];
array[pos1] = array[pos2];
array[pos2] = temp;
}
//Heap class
// E is the element in heap
//Comp is a class used to compare two elements
//Helper function to put element in its correct place,and that moves the father node down
template <typename E, typename Comp>
void heap<E, Comp>::siftdown(int pos) {
while (!isLeaf(pos)) {//Stop if pos is a leaf
int j = leftchild(pos);
int rc = rightchild(pos);
if ((rc < n) && Comp::prior(Heap[rc], Heap[j]))
j = rc; //Set j to greater child's value
if (Comp::prior(Heap[pos], Heap[j]))
return; //Done
swap(Heap, pos, j);
pos = j; //Move down
}
}
template <typename E, typename Comp>
heap<E, Comp>::heap(E* h, int num, int max) {
Heap = h;
n = num;
maxsize = max;
buildHeap();
}
//Return current heap size
template <typename E, typename Comp>
int heap<E, Comp>::size()const {
return n;
}
//True if pos is a leaf
template <typename E, typename Comp>
bool heap<E, Comp>::isLeaf(int pos)const {
return ((pos >= n / 2) && (pos < n));
}
//Return leftchild position
template <typename E, typename Comp>
int heap<E, Comp>::leftchild(int pos)const {
return 2 * pos + 1;
}
//Return rightchild position
template <typename E, typename Comp>
int heap<E, Comp>::rightchild(int pos)const {
return 2 * pos + 2;
}
//Return parent position
template <typename E, typename Comp>
int heap<E, Comp>::parent(int pos)const {
return (pos - 1) / 2;
}
//Heapify contents of Heap
template <typename E, typename Comp>
void heap<E, Comp>::buildHeap() {
for (int i = n / 2 - 1; i >= 0; --i) {
siftdown(i);
}
}
//Insert "it" into the heap
template <typename E, typename Comp>
void heap<E, Comp>::insert(const E& it) {
assert(n < maxsize); //Terminate if heap is full
int curr = n++;
Heap[curr] = it; //Start at end of heap
//Move up until curr's parent > curr
while ((curr != 0) && (Comp::prior(Heap[curr], Heap[parent(curr)]))) {
swap(Heap, curr, parent(curr));
curr = parent(curr);
}
}
template <typename E, typename Comp>
E heap<E, Comp>::removefirst() {
assert(n > 0); //Interrupt if heap is empty
swap(Heap, 0, --n); //Swap first with last value.
if (n != 0)siftdown(0); //Siftdown new root val
return Heap[n]; //Return deleted value
}
template <typename E, typename Comp>
E heap<E, Comp>::remove(int pos) {
assert((pos >= 0) && (pos < n)); //Intertupt if it is in bad position
if (pos == n - 1)n--; //Last element,no work to do
else {
swap(Heap, pos, --n); //Swap with last value
while ((pos != 0) && (Comp::prior(Heap[pos], Heap[parent(pos)]))) {
swap(Heap, pos, parent(pos)); //Push up large key
pos = parent(pos);
}
if (n != 0)siftdown(pos); //Push down small key
}
return Heap[n];
}
(这里用到了模板,所以函数实现最好也写在.h文件中,否则需要对每个模板分别实现,即要一一实现heap<char,…>,heap<int,…>,原因是当编译器把E换成一种类型,比如char的时候,它会自己创建一个heap<char>(假设这样称呼)的类,如果实现与声明分开了,那么编译器会去.cpp文件里面找heap<char>的实现,发现没有,所以会报错“有无法解析的符号…”,因为你的实现文件(.cpp)里的E并没有变成char)
第二步,Huffman树创建(主文件)
#include"heap.h"
#include<time.h>
#include<iostream>
using namespace std;
//Huffman tree node abstract base class
template<typename E>
class HuffNode {
public:
virtual ~HuffNode(){} //Base destructor
virtual int weight() = 0; //Return frequency
virtual bool isLeaf() = 0; //Determine type
};
template<typename E> //Leaf node subclass
class LeafNode :public HuffNode<E> {
private:
E it; //Value
int wgt; //Weight
public:
LeafNode(const E& val, int freq) {
it = val;
wgt = freq;
}
int weight() { return wgt; }
E val() { return it; }
bool isLeaf() { return true; }
~LeafNode(){}
};
template<typename E> //Internal node subclass
class IntlNode : public HuffNode<E> {
private:
HuffNode<E>* lc; //Left child
HuffNode<E>* rc; //Right child
int wgt; //Subtree weight
public:
IntlNode(HuffNode<E>* l, HuffNode<E>* r) {
wgt = l->weight() + r->weight();
lc = l;
rc = r;
}
int weight() { return wgt; }
bool isLeaf() { return false; }
HuffNode<E>* left()const { return lc; }
void setLeft(HuffNode<E>* b) {
lc = b;
}
HuffNode<E>* right()const { return rc; }
void setRight(HuffNode<E>* b) {
rc = b;
}
~IntlNode(){}
};
template<typename E>
class HuffTree {
private:
HuffNode<E>* Root; //Tree root
public:
HuffTree(E& val, int freq) { //Leaf constructor
Root = new LeafNode<E>(val, freq);
}
//Internal node construtor
HuffTree(HuffTree<E>* l, HuffTree<E>* r) {
Root = new IntlNode<E>(l->root(), r->root());
}
HuffTree() { Root = NULL; }
~HuffTree(){}
HuffNode<E>* root() { return Root; }
int weight() { return Root->weight(); }
};
template<typename E>
class minTreeComp {
public:
static bool prior(HuffTree<E>* a, HuffTree<E>* b) {
return b->weight() >= a->weight();
}
};
//Build a Huffman tree from a collection of frequencies
template<typename E>
HuffTree<E>* buildHuff(HuffTree<E>** TreeArray, int count) {
heap<HuffTree<E>*, minTreeComp<E>>* forest =
new heap<HuffTree<E>*, minTreeComp<E>>(TreeArray, count, count);
HuffTree<char> *temp1, *temp2, *temp3 = NULL;
while (forest->size() > 1) {
temp1 = forest->removefirst(); //Pull first two trees
temp2 = forest->removefirst(); //off the list
temp3 = new HuffTree<E>(temp1, temp2);
forest->insert(temp3); //Put the new tree back on list
//因为temp3使用的构造函数是树的指针(HuffTree<E>*),而不是节点的指针(HuffNode<E>*)
//所以释放树指针指向的空间,并不会影响节点指针所指向的空间
//(虽然树里面包含了节点的指针,这个节点指针自身的内存被释放了,但是它指向的内存没有被释放)
//即释放temp1与temp2不会影响temp3
delete temp1; //Must delete the remnants(剩余的)
delete temp2; //of the trees we created
}
return temp3;
}
template<typename E>
void traverse(HuffNode<E>* forest) {
if (forest->isLeaf() == true) {
cout <<((LeafNode<E>*)forest)->val()<<" : "<<forest->weight() << endl;
}
else {
cout << forest->weight()<<endl;
traverse(((IntlNode<E>*)forest)->left());
traverse(((IntlNode<E>*)forest)->right());
}
}
int main() {
srand((unsigned int)time(0));
char ch = 'A';
HuffTree<char>** forests= new HuffTree<char>*[7];
//vector<HuffTree<char>*>trees;
for (int i = 0; i < 7; ++i) {
ch += 1;
forests[i]= new HuffTree<char>(ch,rand() % 50 + 1);
}
HuffTree<char>* forest = buildHuff(forests, 7);
traverse(forest->root());
}
运行结果
Reference
《数据结构与算法分析(C++版)(第三版)》P115,P121