今天,我们一起使用模板来写一个哈夫曼编码类,具体如例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; } #endifmain.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 运行效果
今天,我们共同使用模板完成了哈夫曼编码,希望大家回去多实践,熟练模板的使用。