实验目的
- 理解并熟练掌握哈夫曼编码原理
- 利用各种编程语言能够实现数字图像的哈夫曼编码算法
实验内容
- 编程实现数字图像的哈夫曼编码算法
- 利用所实现的上述算法,通过下面具体的实例,给出哈夫曼算法运行的结果,即显示出编码及码字长度(给出截图):
一幅40像素的黑白图像,有8个不同等级的亮度(灰度),分别用符号A—H表示,这些像素出现各种灰度的数量及概率如下图所示。
实验要求
- 独立完成(但可以相互交流),禁止拷贝他人代码和实验结果,一经发现,将无实验成绩。
- 程序运行界面要显示出个人信息(班级、姓名、学号)。
- 实验过程要详细。
实验过程(算法实现)
include <iostream>
#include <queue>
#include <vector>
using namespace std;
struct Node{
char c;
int n;
Node* left;
Node* right;
Node(char _c, int _n): c(_c), n(_n), left(nullptr), right(nullptr) {}
Node(char _c, int _n, Node* l, Node* r): c(_c), n(_n) {
left = l;
right = r;
}
};
struct cmp {
bool operator()(Node*& a, Node*& b) const {
return a->n > b->n;
}
};
struct HuffmanTree{
// 利用小根堆来自动排序
priority_queue<Node*, vector<Node*>, cmp> heap;
HuffmanTree() {
cout << "请依次输入若干不同等级灰度的符号和出现频数,以频数0为结束:" << endl;
char c;
int n;
while (cin >> c >> n && n) heap.push(new Node(c, n));
while (heap.size() > 1) {
// 每次取出频数最小的两个节点
Node* t1 = heap.top();
heap.pop();
Node* t2 = heap.top();
heap.pop();
// 合并为一个节点,再插回堆中,起到排序的作用
heap.push(new Node('0', t1->n + t2->n, t1, t2));
}
// 最后小根堆中就剩一个节点,就是哈夫曼树的根节点
}
// 遍历打印哈夫曼树
void dfs(Node* u, string path) {
if (!u->left && !u->right) cout << u->c << '\t' << u->n << '\t' << path << endl;
if (u->left) dfs(u->left, path + '0');
if (u->right) dfs(u->right, path + '1');
}
~HuffmanTree() {
while (heap.size()) {
Node* t = heap.top();
heap.pop();
if (t->left) heap.push(t->left);
if (t->right) heap.push(t->right);
// cout << "删除节点:" << t->c << endl;
delete t;
}
}
};
int main() {
HuffmanTree ht;
cout << "符号\t频数\t编码" << endl;
ht.dfs(ht.heap.top(), "");
return 0;
}
实验结果
实验结果分析
频数或频率越高的符号的编码长度越短,越低的符号编码长度越长;且任何一个编码都不是其他任何编码的前缀,即不会产生歧义。