备考期末,懂得都懂,不懂就别看了,挺浪费时间的;
哈夫曼树的构建c/c++实现
结构定义
typedef char ElemType;
typedef struct{
ElemType data;
int weight;
int parent, lchild, rchild;
} HuffNode;
初始化哈夫曼树结构
HuffNode *initial_hufT(){
int n = 0;
cin >> n; //叶子结点数n
int numNode = 2 * n - 1;
HuffNode *HT = new HuffNode[numNode + 1];
//结点初始化
for (int i = 1; i <= numNode; i++) // 将所有结点的双亲和孩子信息置为0
HT[i].weight = HT[i].data = HT[i].lchild = HT[i].rchild = HT[i].parent = 0;
//对结点设置权值
for (int i = 1; i <= n; i++)
cin >> HT[i].weight;
for (int i = 1; i <= n; i++)
cin >> HT[i].data;
//树的节点数记录
HT[0].data = n;
HT[0].weight = numNode;
return HT;
}
选择权值最小两个结点(生成哈夫曼树用)
//从HT[1]~HT[n]中选取parent为0的,对weight进行排序,并找出最小的两个weight的下标存进s1和s2
void Select(HuffNode *HT, int n, int &T1, int &T2){
map<int, int> m;
for (int i = 1; i <= n; i++)
if (!HT[i].parent)
m.insert(make_pair(HT[i].weight, i)); // insert 函数插入 pair 数据
map<int, int>::iterator mTemp = m.begin();
T1 = (*mTemp++).second;
T2 = (*mTemp).second;
}
生成哈夫曼树
void createHuFTree(HuffNode *HT){
int T1, T2;
for (int i = HT[0].data + 1; i <= HT[0].weight; i++){
Select(HT, i - 1, T1, T2);
HT[T1].parent = HT[T2].parent = i; //删除结点
//合并结点
HT[i].lchild = T1;
HT[i].rchild = T2;
HT[i].weight = HT[T1].weight + HT[T2].weight;
}
}
打印输出哈夫曼树存储结构所有结点的信息(debug用)
void PrintHuFTree(HuffNode *HT)
{
cout << "index" << '\t' << "data" << '\t' << "weight" << '\t' << "parent" << '\t' << "lChild" << '\t' << "rChild" << endl;
for (int i = 1; i <= HT[0].weight; ++i)
{
cout << i << "\t";
cout << HT[i].data << '\t';
cout << HT[i].weight << '\t';
cout << HT[i].parent << "\t";
cout << HT[i].lchild << "\t";
cout << HT[i].rchild << endl;
}
}
生成哈夫曼编码表
注意是从数据结点(通过父亲结点下标)向上遍历到root;借助栈来实现正向输出编码,然后将其存放到map中;
void PrintHuFTreeCode(HuffNode *HT , map<char , string> &codeDict){
for (int i = 1; i <= HT[0].data; i++){
stack<char> CodeStack;
HuffNode *TempNode = &HT[i];
HuffNode *TF = &HT[TempNode->parent];
while (true){
if (&HT[TF->lchild] == TempNode) CodeStack.push('0'); //判断当前结点是父亲节点的左节点还是右节点
else CodeStack.push('1');
TempNode = TF;
if(!TF->parent) break;
TF = &HT[TF->parent];
} //从叶子结点向上遍历到root
// 输出 哈夫曼编码
// cout<< HT[i].weight << ": ";
string t = "";
while (!CodeStack.empty()){
// cout << CodeStack.top();
t += CodeStack.top();
CodeStack.pop();
}
// cout << endl;
codeDict.insert( make_pair( HT[i].data, t) );
}
}
根据哈夫曼编码表解码字符串
void DehufCode(HuffNode *HT , map<char , string> codeDict){
for(auto i = codeDict.begin();i!=codeDict.end() ;i++) // 输出编码表
cout<< i->first << ": " << i->second << endl;
string cT;
cin >> cT;
cout << "cipherText: " << "{" << cT << "}" << endl;
cout << "decode Text: " << "{" ;
while (cT.length() )
for(auto i = codeDict.begin();i!=codeDict.end() ;i++){
int index = cT.find(i->second);
if(!index) //匹配
{
cout << i->first;
cT.erase(0, i->second.length() );
}
}
cout << "}" << endl;
}
总代码
#include <map>
#include <stack>
#include <string>
#include <iostream>
using namespace std;
typedef char ElemType;
typedef struct{
ElemType data;
int weight;
int parent, lchild, rchild;
} HuffNode;
HuffNode *initial_hufT(){
int n = 0;
cin >> n; //叶子结点数n
int numNode = 2 * n - 1;
HuffNode *HT = new HuffNode[numNode + 1];
//结点初始化
for (int i = 1; i <= numNode; i++) // 将所有结点的双亲和孩子信息置为0
HT[i].weight = HT[i].data = HT[i].lchild = HT[i].rchild = HT[i].parent = 0;
//对结点设置权值
for (int i = 1; i <= n; i++)
cin >> HT[i].weight;
for (int i = 1; i <= n; i++)
cin >> HT[i].data;
//树的节点数记录
HT[0].data = n;
HT[0].weight = numNode;
return HT;
}
//从HT[1]~HT[n]中选取parent为0的,对weight进行排序,并找出最小的两个weight的下标存进s1和s2
void Select(HuffNode *HT, int n, int &T1, int &T2){
map<int, int> m;
for (int i = 1; i <= n; i++)
if (!HT[i].parent)
m.insert(make_pair(HT[i].weight, i)); // insert 函数插入 pair 数据
map<int, int>::iterator mTemp = m.begin();
T1 = (*mTemp++).second;
T2 = (*mTemp).second;
}
// 创建哈夫曼树
void createHuFTree(HuffNode *HT){
int T1, T2;
for (int i = HT[0].data + 1; i <= HT[0].weight; i++){
Select(HT, i - 1, T1, T2);
HT[T1].parent = HT[T2].parent = i; //删除结点
//合并结点
HT[i].lchild = T1;
HT[i].rchild = T2;
HT[i].weight = HT[T1].weight + HT[T2].weight;
}
}
//打印输出哈夫曼树所有叶子结点信息
void PrintHuFTree(HuffNode *HT)
{
cout << "index" << '\t' << "data" << '\t' << "weight" << '\t' << "parent" << '\t' << "lChild" << '\t' << "rChild" << endl;
for (int i = 1; i <= HT[0].weight; ++i)
{
cout << i << "\t";
cout << HT[i].data << '\t';
cout << HT[i].weight << '\t';
cout << HT[i].parent << "\t";
cout << HT[i].lchild << "\t";
cout << HT[i].rchild << endl;
}
}
void PrintHuFTreeCode(HuffNode *HT , map<char , string> &codeDict){
for (int i = 1; i <= HT[0].data; i++){
stack<char> CodeStack;
HuffNode *TempNode = &HT[i];
HuffNode *TF = &HT[TempNode->parent];
while (true){
if (&HT[TF->lchild] == TempNode) CodeStack.push('0'); //判断当前结点是父亲节点的左节点还是右节点
else CodeStack.push('1');
TempNode = TF;
if(!TF->parent) break;
TF = &HT[TF->parent];
} //从叶子结点向上遍历到root
// 输出 哈夫曼编码
// cout<< HT[i].weight << ": ";
string t = "";
while (!CodeStack.empty()){
// cout << CodeStack.top();
t += CodeStack.top();
CodeStack.pop();
}
// cout << endl;
codeDict.insert( make_pair( HT[i].data, t) );
}
}
// 根据哈夫曼树解码字符串
void DehufCode(HuffNode *HT , map<char , string> codeDict){
// 演示用
for(auto i = codeDict.begin();i!=codeDict.end() ;i++)
cout<< i->first << ": " << i->second << endl;
string cT;
cin >> cT;
cout << "cipherText: " << "{" << cT << "}" << endl;
cout << "decode Text: " << "{" ;
while (cT.length() )
for(auto i = codeDict.begin();i!=codeDict.end() ;i++){
int index = cT.find(i->second);
if(!index) //匹配
{
cout << i->first;
cT.erase(0, i->second.length() );
}
}
cout << "}" << endl;
}
int main(){
HuffNode *HT = initial_hufT();
map<char , string> codeDict;
createHuFTree(HT);
PrintHuFTree(HT);
PrintHuFTreeCode(HT, codeDict);
DehufCode(HT, codeDict);
cin.get();
cin.get();
return 0;
}
运行示例
5 15 7 6 6 5 A B C D E
index data weight parent lChild rChild
1 A 15 9 0 0
2 B 7 7 0 0
3 C 6 6 0 0
4 D 6 7 0 0
5 E 5 6 0 0
6 11 8 5 3
7 13 8 4 2
8 24 9 6 7
9 39 0 1 8
A: 0
B: 111
C: 101
D: 110
E: 100
1001101011110
cipherText: {1001101011110}
decode Text: {EDCBA}