/* Huffman类:哈夫曼树
* 接口:
* MakeEmpty:重置功能,重置哈夫曼树
* DisSt:展示编码表
* IsLeaf:判断对应节点是否为叶子节点
* GetFreq:获取权重数组
* BuildTree:根据权重数组构建哈夫曼树
* BuildCode:根据哈夫曼树构建编码表
* Expend:根据哈夫曼树展开压缩文本
* Compress:根据编码表压缩原始文本
*/
class Huffman
{
public:
// 构造函数
Huffman();
// 析构函数
~Huffman();
// 接口函数
void MakeEmpty();
void DisSt();
bool IsLeaf(Node*);
void GetFreq(int);
void BuildTree();
void BuildCode();
string Expend(string);
string Compress(string);
private:
// 辅助功能函数
void MakeEmpty(Node *);
void BuildCode(Node *, string);
// 数据成员
const int R = 128;
int *freq; // 权重数组
string *st; // 编码表
Node *Root; // 哈夫曼树根
};
struct Node {
// 储存元素
char ch;
int weigth;
Node *Left;
Node *Right;
// 构造函数
Node() {
Left = NULL;
Right = NULL;
}
// 拷贝构造函数
Node(const Node &P) {
ch = P.ch;
weigth = P.weigth;
if (P.Left == NULL)
Left = NULL;
else {
Left = new Node();
*Left = *(P.Left);
}
if (P.Right == NULL)
Right = NULL;
else {
Right = new Node();
*Right = *(P.Right);
}
}
// 重载"<="符号
bool operator <= (const Node &P) {
return this->weigth <= P.weigth;
}
};
/* 构建函数:根据权重数组构建哈夫曼树
* 参数:无
* 返回值:无
*/
void Huffman::BuildTree() {
// 储存配对堆
PairHeap ph;
// 将所有的字母生成对于的节点存入配对堆中
for(int c = 0; c < R; c++)
if (freq[c] > 0) {
Node *NewNode = new Node();
NewNode->ch = c;
NewNode->Left = NewNode->Right = NULL;
NewNode->weigth = freq[c];
ph.Insert(*NewNode);
}
// 将配对堆中最小的两个节点取出,进行合并,将合并后的节点重新加入配对堆
// 特别注意:
// 对于Node,应该处理其拷贝构造函数,因为我们将对其进行深拷贝
while (ph.size() > 1) {
Node *x = &ph.Top();
ph.DeleteMin();
Node *y = &ph.Top();
ph.DeleteMin();
Node *Parent = new Node();
Parent->ch = '\0';
Parent->Left = x;
Parent->Right = y;
Parent->weigth = x->weigth + y->weigth;
ph.Insert(*Parent);
}
// 储存根节点同时特殊处理,防止因数据析构而消失
Root = new Node();
*Root = ph.Top();
ph.DeleteMin();
}
/* 编码函数:根据哈夫曼树构建编码表
* 参数:无
* 返回值:无
*/
void Huffman::BuildCode() {
if(Root != NULL)
BuildCode(Root, "");
}
/* 编码函数:根据对应节点信息进行编码
* 参数:T:当前的编码节点,s:当前的编码信息
* 返回值:无
*/
void Huffman::BuildCode(Node *T, string s) {
// 递归终止条件
if (IsLeaf(T)) {
st[T->ch] = s;
return;
}
// 递归的对下一层节点进行编码
BuildCode(T->Left, s + '0');
BuildCode(T->Right, s + '1');
}
/* 展开函数:根据哈夫曼树展开压缩文本
* 参数:txt:想要进行展开的压缩文本
* 返回值:string:压缩文本展开后的字符串
*/
string Huffman::Expend(string txt) {
// 储存展开结果
string re;
// 遍历整个目标文本
for (int i = 0; i < txt.length(); ) {
if (txt[i] == '#')
break;
Node *x = Root;
// 获取压缩信息
while (!IsLeaf(x)) {
if (txt[i] == '0')
x = x->Left;
else
x = x->Right;
i++;
}
// 更新结果文本
re += x->ch;
}
return re;
}
/* 压缩函数:根据编码表压缩原始文本
* 参数:txt:想要进行压缩的原始文本
* 返回值:string:原始文本压缩后的字符串
*/
string Huffman::Compress(string txt) {
// 储存压缩结果
string re;
// 遍历原始文本同时读取编码表
for (int i = 0; i < txt.length(); i++)
re += st[txt[i]];
return re;
}
参考文献:《算法——第四版》