今天,我们一起使用模板来写一个哈夫曼编码类,具体如例1所示。
例1 对下面字符进行编码,使其总体长度最短。
字母={A,B,C,D,E},频率={15,7,6,6,5},字母和频率一一对应。
分析:解决这道题目的方法是使用哈夫曼编码,哈夫曼编码利用哈夫曼树构造前缀编码,使文本总体长度最短。
具体实现如下:
Huffman.hpp内容:
#ifndef _HUFFMAN_H_
#define _HUFFMAN_H_
#include <vector>
#include <string>
#include <iostream>
using namespace std;
template<typename T>
struct Node
{
T m_Data;
string m_strName;
};
template<typename T>
struct TreeNode
{
Node<T> m_Info;
TreeNode * m_pParent;
TreeNode * m_pLeft;
TreeNode * m_pRight;
};
template<typename T>
class CHuffmanTree
{
public:
CHuffmanTree();
~CHuffmanTree();
//初始化哈夫曼树
bool InitForest(vector<Node<T> > & v);
//构建哈夫曼树
bool BuildHuffman();
//销毁
void Clear();
//打印huffman编码
void PrintEncode();
private:
//销毁树
void ClearTree(TreeNode<T> * pRoot);
//中序遍历
void InOrderTree(TreeNode<T> * pRoot);
private:
vector<TreeNode<T> *> m_vForest;
TreeNode<T> * m_pRoot;
};
template<typename T>
CHuffmanTree<T>::CHuffmanTree()
{
m_pRoot = NULL;
}
template<typename T>
CHuffmanTree<T>::~CHuffmanTree()
{
vector<TreeNode<T> *>::iterator it;
for (it = m_vForest.begin(); it != m_vForest.end(); it++)
{
if (*it)
ClearTree(*it);
}
m_vForest.clear();
if (m_pRoot)
{
ClearTree(m_pRoot);
m_pRoot = NULL;
}
}
template<typename T>
bool CHuffmanTree<T>::InitForest(vector<Node<T> > & vWeights)
{
TreeNode<T> * pNewNode = NULL;
vector<Node<T> >::iterator it;
for (it = vWeights.begin(); it != vWeights.end(); it++)
{
pNewNode = new TreeNode<T>;
if (!pNewNode)
{
return false;
}
pNewNode->m_Info.m_Data = it->m_Data;
pNewNode->m_Info.m_strName = it->m_strName;
pNewNode->m_pParent = NULL;
pNewNode->m_pLeft = NULL;
pNewNode->m_pRight = NULL;
m_vForest.push_back(pNewNode);
}
return true;
}
//构建哈夫曼树
template<typename T>
bool CHuffmanTree<T>::BuildHuffman()
{
TreeNode<T> * pMin = NULL;
TreeNode<T> * pMin2 = NULL;
TreeNode<T> * pNewNode = NULL;
vector<TreeNode<T> *>::iterator it;
vector<TreeNode<T> *>::iterator itMin;
vector<TreeNode<T> *>::iterator itMin2;
while (m_vForest.size() > 1)
{
pNewNode = new TreeNode<T>;
if (!pNewNode)
return false;
pMin = m_vForest[0];
itMin = m_vForest.begin();
for (it = m_vForest.begin(); it != m_vForest.end(); it++)
{
if ((*it)->m_Info.m_Data < pMin->m_Info.m_Data)
{
pMin = *it;
itMin = it;
}
}
m_vForest.erase(itMin);
pMin2 = m_vForest[0];
itMin2 = m_vForest.begin();
for (it = m_vForest.begin(); it != m_vForest.end(); it++)
{
if (((*it)->m_Info.m_Data < pMin2->m_Info.m_Data) && (*it != pMin))
{
pMin2 = *it;
itMin2 = it;
}
}
m_vForest.erase(itMin2);
pNewNode->m_pLeft = pMin;
pNewNode->m_pRight = pMin2;
pNewNode->m_pParent = NULL;
pNewNode->m_Info.m_Data = (pMin)->m_Info.m_Data + (pMin2)->m_Info.m_Data;
pNewNode->m_Info.m_strName = (pMin)->m_Info.m_strName + (pMin2)->m_Info.m_strName;
m_vForest.push_back(pNewNode);
}
m_pRoot = m_vForest[0];
m_vForest.clear();
return true;
}
template<typename T>
void CHuffmanTree<T>::Clear()
{
vector<TreeNode<T> *>::iterator it;
for (it = m_vForest.begin(); it != m_vForest.end(); it++)
{
if (*it)
ClearTree(*it);
}
m_vForest.clear();
if (m_pRoot)
{
ClearTree(m_pRoot);
m_pRoot = NULL;
}
}
template<typename T>
void CHuffmanTree<T>::InOrderTree(TreeNode<T> * pRoot)
{
vector<int>::iterator it;
static vector<int> vPath;
if (!pRoot)
return;
if (pRoot->m_pLeft)
{
vPath.push_back(0);
InOrderTree(pRoot->m_pLeft);
}
if ((pRoot->m_pLeft == NULL) && (pRoot->m_pRight == NULL))
{
cout << pRoot->m_Info.m_strName << "编码:";
for (it = vPath.begin(); it != vPath.end(); it++)
{
cout << *it;
}
cout << endl;
}
if (pRoot->m_pRight)
{
vPath.push_back(1);
InOrderTree(pRoot->m_pRight);
}
if (!vPath.empty())
vPath.pop_back();
return;
}
template<typename T>
void CHuffmanTree<T>::PrintEncode()
{
if (m_pRoot)
InOrderTree(m_pRoot);
else
cout << "Huffman Tree is empty." << endl;
}
template<typename T>
void CHuffmanTree<T>::ClearTree(TreeNode<T> * pRoot)
{
if (!pRoot)
return;
if (pRoot->m_pLeft)
ClearTree(pRoot->m_pLeft);
if (pRoot->m_pRight)
ClearTree(pRoot->m_pRight);
delete pRoot;
return;
}
#endif
main.cpp内容:
#include "Huffman.hpp"
void main()
{
CHuffmanTree<int> HuffmanTree;
vector<Node<int>> v;
Node<int> tmp;
tmp.m_strName = "A";
tmp.m_Data = 15;
v.push_back(tmp);
tmp.m_strName = "B";
tmp.m_Data = 7;
v.push_back(tmp);
tmp.m_strName = "C";
tmp.m_Data = 6;
v.push_back(tmp);
tmp.m_strName = "D";
tmp.m_Data = 6;
v.push_back(tmp);
tmp.m_strName = "E";
tmp.m_Data = 5;
v.push_back(tmp);
HuffmanTree.InitForest(v);
HuffmanTree.BuildHuffman();
HuffmanTree.PrintEncode();
HuffmanTree.Clear();
system("pause");
}
运行效果如图1所示:
图1 运行效果
今天,我们共同使用模板完成了哈夫曼编码,希望大家回去多实践,熟练模板的使用。