使用静态链表与伪指针(即数组)实现Huffman树
//
// main.cpp
// HuffmanTree
//
// Created by Cyril on 2016/12/8.
// Copyright © 2016年 Cyril. All rights reserved.
//
#include <iostream>
#include <string>
#include <cfloat>
#define MAXSIZE 1005
using namespace std;
//霍夫曼树结点类
template <class T>
class HTNode
{
public:
T data;
double weight;
int parent;
int lChild;
int rChild;
};
//霍夫曼编码类
class HCode
{
public:
char code[MAXSIZE];//存放当前结点的霍夫曼编码
int start;//用start来存放霍夫曼编码的最开始字符
};
//霍夫曼树
//对于具有n个叶子结点的霍夫曼树,共有2n-1个结点,ht[0~n-1]存放叶子结点,ht[n~2n-2]存放需要构造的非叶子结点
template <class T>
class HT
{
private:
int wnum;//权值个数
HTNode<T> ht[MAXSIZE];//存放霍夫曼树
HCode hCode[MAXSIZE];//存放霍夫曼编码
public:
void SetValue(T *data, double *weight, int len);//设置初值
void CreateHT();//构造霍夫曼树
void Encode();//求霍夫曼编码
void DispHCode();//输出霍夫曼编码
void Decode(string str);//根据编码求数据
};
template <class T>
void HT<T>:: SetValue(T *data, double *weight, int len) {
for (int i=0; i<len; i++) {
ht[i].data=data[i];
ht[i].weight=weight[i];
}
wnum=len;
}
template <class T>
void HT<T>:: CreateHT() {
int lNode,rNode;//存放左结点与右结点
double min1,min2;//存放两个最小的权值
for (int i=0; i<(2*wnum-1); i++)
ht[i].parent=ht[i].lChild=ht[i].rChild=-1;//初始化都赋值为-1
for (int i=wnum; i<(2*wnum-1); i++) {
min1=min2=DBL_MAX;//初始化最大值
lNode=rNode=-1;//lNode与rNode为两个权值最小的结点位置
for (int j=0; j<=i-1; j++)
if (ht[j].parent==-1) {//遍历根结点
if (ht[j].weight<min1) {//找出新的最小值
min2=min1;
rNode=lNode;
min1=ht[j].weight;
lNode=j;
} else if (ht[j].weight<min2) {//找到次小值
min2=ht[j].weight;
rNode=j;
}
}
ht[lNode].parent=ht[rNode].parent=i;//合并为同一个父亲结点
ht[i].weight=ht[lNode].weight+ht[rNode].weight;
ht[i].lChild=lNode;
ht[i].rChild=rNode;//ht[i]即是父亲结点
}
}
template <class T>
void HT<T>:: Encode() {
int c,p;//c存放孩子的位置,p存放父亲的位置,用于递推循环
for (int i=0; i<wnum; i++) {//遍历叶子结点
hCode[i].start=wnum;//从hcode[i].code[wnum]开始放置霍夫曼编码,按照逆序
c=i;
p=ht[i].parent;
while (p!=-1) {//循环直到无父亲结点,即根结点
if (ht[p].lChild==c)
hCode[i].code[hCode[i].start]='0';//若该结点为左孩子结点,编码置为0
else
hCode[i].code[hCode[i].start]='1';//若该结点为右孩子结点,编码置为1
hCode[i].start--;
c=p;
p=ht[p].parent;
}
hCode[i].start++;//返回一位,存放编码最开始字符
}
}
template <class T>
void HT<T>:: DispHCode() {
cout<<"The Huffman codes are: "<<endl;
for (int i=0; i<wnum; i++) {
cout<<ht[i].data<<':';
for (int j=hCode[i].start; j<=wnum; j++) {
cout<<hCode[i].code[j];
}
cout<<endl;
}
}
template <class T>
void HT<T>:: Decode(string str) {
int len=(int)str.length();
int i=0,j=2*wnum-2;//下标指针,i用于遍历str字符串,j用来遍历树,树的根结点为2*wnum-2
T temp=0;//存取读取的数据
while (len--) {
temp=((str[i]=='0')?ht[ht[j].lChild].data:ht[ht[j].rChild].data);//左右孩子的数据
j=((str[i]=='0')?ht[j].lChild:ht[j].rChild);
i++;
}
if(temp)
cout<<"The data you wanted is: "<<temp<<endl;
else
cout<<"Can't find the data you wanted!"<<endl;
}
int main()
{
string str;
HT<char> HFMTree;
double w[4]={7,5,2,4};
char d[4]={'a','b','c','d'};
HFMTree.SetValue(d,w,4);
HFMTree.CreateHT();
HFMTree.Encode();
HFMTree.DispHCode();
cout<<"Please input the code: ";
cin>>str;
HFMTree.Decode(str);
return 0;
}
程序运行结果如下: