实验八:最优树Huffman 算法求解
- 实验目的和要求
实验目的:
Huffman 算法的一个经典应用就是 Huffman 编码,结合在图论部分对二元树这种图结构的学习,了解该算法在数据通信编码、图像压缩编码中的最直接应用。主要描述为:数据通信中经常需要将传送的内容转换成二进制编码,Huffman 编码是一种变长的编码方案,其核心是使频率越高的码采用越短的编码方式,同时所有码在解码时不会出现二义性。
理解最优二元树的编码原理,并借助 Huffman 算法实现最优树求解。
实验要求:
(1).借助已有平台基于 Huffman 算法求解实验最优二元树的求解。
(2).或自行编码实现最优二元树的求解及结果展示。
2. 实验环境和工具
开发环境:Visual Studio 2019
3. 实验结果
3.1 程序流程图
3.2 程序代码 (仅供参考,水平有限,有错请指出)
#include<iostream>
#include<fstream>
#include<vector>
#include<stack>
#include<algorithm>
#include<string>
#include<unordered_map>
#include<queue>
using namespace std;
class Hnode
{
public:
Hnode(int w, char a)
{
this->weight = w;
this->data = a;
this->lchild = NULL;
this->rchild = NULL;
}
Hnode()
{
this->weight = 0;
this->lchild = NULL;
this->rchild = NULL;
}
string code;//哈夫曼编码(string型)
//int* code;//哈夫曼编码(int型)
int weight;//权值
char data;//字符
Hnode* lchild;//左子树
Hnode* rchild;//右子树
};
class HuffmanTree
{
public:
HuffmanTree();//构造函数,读取文件创建与字符数相等的动态数组
Hnode* get_root();//取根结点
void Coding(Hnode* p);//编码
void input();//从文件中读入原文
void creat();//建树
void sort(int size);//构建过程中的排序
Hnode* combine(Hnode* t1, Hnode* t2);//取两个最小权值结点结合
void Delete(Hnode* insert, int size);//结合后删除列表中那两个被结合的结点
void read();//读取文件中的原文
void load_code(Hnode* p);//将字符与对应的编码储存到数组中
void Print(Hnode* p);//大音哈夫曼树
void Mid(Hnode* p);//中序遍历哈夫曼树
private:
int weight[126] = { 0 };
int num;
Hnode** w;
Hnode* root;
string a[126];//存码表
vector<Hnode*>v;
};
HuffmanTree::HuffmanTree()
{
this->read();
w = new Hnode * [num];
}
Hnode* HuffmanTree::get_root()
{
return this->root;
}
void HuffmanTree::Mid(Hnode* p)
{
if (p != NULL)
{
Mid(p->lchild);
v.push_back(p);
Mid(p->rchild);
}
}
void HuffmanTree::Print(Hnode* p)
{
string template_str;//模板string,表示每行打印string的长度
int location = 0;
unordered_map<Hnode*, int> first_locations;//存储节点对应在本行string中的首位置
for (auto& i : v)
{
location = template_str.size();
template_str += to_string(i->weight) + " ";
first_locations[i] = location;
}
for (auto& i : template_str)//把模板全部置为空格方便后续使用
i = ' ';
queue<Hnode*> q;//逐层按序遍历
q.push(p);
while (!q.empty())
{
int currentLevelSize = q.size();
int cur_loc = 0;
string tmp_str1 = template_str, tmp_str2 = template_str;//1为节点所在行,2为其下一行
for (int i = 1; i <= currentLevelSize; ++i)
{
Hnode* node = q.front();
q.pop();
cur_loc = first_locations[node];
string num_str = to_string(node->weight);
//左边,如果存在左孩子,那么在第二行对应位置打印'/',在第一行补上'_'
if (node->lchild)
{
q.push(node->lchild);
int first_loc = first_locations[node->lchild] + 1;
tmp_str2[first_loc++] = '/';
while (first_loc < cur_loc)tmp_str1[first_loc++] = '_';
}
//中间,对应位置打印节点值(有可能为多位数)
for (int j = 0; j < num_str.length(); ++j, ++cur_loc)
{
tmp_str1[cur_loc] = num_str[j];
}
//右边,如果存在右孩子,那么在第二行对应位置打印'\',在第一行补上'_'
if (node->rchild)
{
q.push(node->rchild);
int last_loc = first_locations[node->rchild] - 1;
tmp_str2[last_loc] = '\\';
while (cur_loc < last_loc)
{
tmp_str1[cur_loc++] = '_';
}
}
}
//打印两行
cout << tmp_str1 <<endl;
cout << tmp_str2 <<endl;
}
}
void HuffmanTree::load_code(Hnode* p)
{
if (p != NULL)
{
if (p->data != NULL)
{
a[int(p->data)] = p->code;
}
load_code(p->lchild);
load_code(p->rchild);
}
}
void HuffmanTree::read()
{
ifstream ifs;
ifs.open("original_test1.txt", ios::in);
if (!ifs.is_open())
{
cout << "文件打开失败" << endl;
return;
}
string file;
while (!ifs.fail())
{
string buf;
getline(ifs, buf);
file += buf;
file += '\n';
}
file.pop_back();
file.pop_back();
for (int i = 0; i < file.size(); i++)
{
weight[int(file[i])]++;
}
this->num = 0; int j = 0;
for (; j < 126; j++)
{
if (weight[j] != 0)
{
num++;
}
}
ifs.close();
}
void HuffmanTree::input()
{
int j = 0, k = 0;
for (; j < 126; j++)
{
if (weight[j] != 0)
{
w[k] = new Hnode(weight[j], char(j));
k++;
}
}
}
void HuffmanTree::sort(int size)
{
Hnode* temp = new Hnode;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size - 1 - i; j++)
{
if (w[j]->weight > w[j + 1]->weight)
{
temp = w[j];
w[j] = w[j + 1];
w[j + 1] = temp;
}
}
}
}
Hnode* HuffmanTree::combine(Hnode* t1, Hnode* t2)
{
Hnode* temp = new Hnode;
temp->weight = t1->weight + t2->weight;
temp->lchild = t1;
temp->rchild = t2;
return temp;
}
void HuffmanTree::Delete(Hnode* insert, int size)
{
w[0] = insert;
for (int i = 1; i < size - 1; i++)
w[i] = w[i + 1];
}
void HuffmanTree::creat()
{
for (int i = 0; i < num - 1; i++)
{
sort(num - i);
root = combine(w[0], w[1]);
Delete(root, num - i);
}
}
void HuffmanTree::Coding(Hnode* p)
{
if (p != NULL)
{
if (p->lchild != NULL)
{
p->lchild->code = p->code + '0';
}
if (p->rchild != NULL)
{
p->rchild->code = p->code + '1';
}
//if (p->data != '\0')
cout << "字符:" << p->data << " 权值:" << p->weight << " 编码:" << p->code << endl;
Coding(p->lchild);
Coding(p->rchild);
}
}
int main()
{
HuffmanTree H;
H.input();
H.creat();
cout << "哈夫曼编码如下:" << endl;
H.Coding(H.get_root());
H.load_code(H.get_root());
H.Mid(H.get_root());
H.Print(H.get_root());
return 0;
}
3.3 运行结果
其他实验:
合肥工业大学2021离散数学上机实验一https://blog.csdn.net/qq_52791068/article/details/122654230
合肥工业大学2021离散数学上机实验四https://blog.csdn.net/qq_52791068/article/details/122656507
合肥工业大学2021离散数学上机实验六https://blog.csdn.net/qq_52791068/article/details/122656801