【数据结构】赫夫曼编码及其应用

题目

1.背景知识

二叉树的应用、赫夫曼树。

2.目的要求

掌握赫夫曼树和赫夫曼编码的基本思想和算法的程序实现。

3.实验内容

实现文件中数据的加解密与压缩:将硬盘上的一个文本文件进行加密,比较加密文件和原始文件的大小差别;对加密文件进行解密,比较原始文件和解码文件的内容是否一致。

4.实验说明

  1. 输入和输出:
    (1)输入:硬盘上给定的原始文件及文件路径。
    (2)输出:
     硬盘上的加密文件及文件路径;
     硬盘上的解码文件及文件路径;
     原始文件和解码文件的比对结果。
  2. 实验要求:
     提取原始文件中的数据(包括中文、英文或其他字符),根据数据出现的频率为权重,构建Huffman编码表;
     根据Huffman编码表对原始文件进行加密,得到加密文件并保存到硬盘上;
     将加密文件进行解密,得到解码文件并保存到硬盘上;
     比对原始文件和解码文件的一致性,得出是否一致的结论。
  3. 参考类型定义 //双亲孩子表示法
   	typedef struct {
            unsigned int  weight;
            unsigned int  parent, lchild, rchild;
        } HTNode, *HuffmanTree;      // 动态分配数组存储赫夫曼树
	typedef char * * HuffmanCode;  // 动态分配数组存储赫夫曼编码表

5.注意问题:

  1. 本实验涉及到赫夫曼树和赫夫曼编码基本思想和构建方法;C语言文件的建立、读取、写入方法;C语言位运算等知识。
  2. 请在实验报告中说明Huffman编码表的构建过程。

解答

1.文件要求

代码和源文件 r e s o u r c e . t x t resource.txt resource.txt (内容可以自定义)要在同一目录下,运行代码后在目录下会生成两个文件 H u f f m a n C o d e . t x t ,   T r a n s l a t e d F i l e . t x t Huffman Code.txt,~Translated File.txt HuffmanCode.txt, TranslatedFile.txt,分别存放源文件编码后的内容、编码后的文件解码出的内容。
如下:在这里插入图片描述
C o d e Code Code

#include <bits/stdc++.h>
using namespace std;

typedef struct{
	unsigned int weight;
	unsigned int parent, lchild, rchild;
	char c;
}ht_node, *huffman_tree;

typedef char** huffman_code;

string vs;
map<char, int> power; // 每个字符的出现次数/权值
vector<int> ch_list;
vector<int> pw_list; // 权值的有序集合
map<char, string> mp; // 字符->编码
int n;
int s1, s2;
string vs_ht; // 生成的Huffman编码
map<string, char> mp_ht; // 编码->字符
string s_trans; // 解压好的字符串

void select(huffman_tree &ht, int ed) {
	int minn = 0x3f3f3f3f;
	for (int i = 1; i <= ed; i ++) {
		if (ht[i].parent == 0 && ht[i].weight < minn) {
			minn = ht[i].weight;
			s1 = i;
		}
	}
	minn = 0x3f3f3f3f;
	for (int i = 1; i <= ed; i ++) {
		if (ht[i].parent == 0 && ht[i].weight < minn && i != s1) {
			minn = ht[i].weight;
			s2 = i;
		}
	}
}

void huffman_coding(huffman_tree &ht) {
	if (n <= 1) {
		return;
	}
	
	int m = 2 * n - 1; // 树共m个节点
	ht = (huffman_tree)malloc((m + 1) * sizeof(ht_node));
	ht_node *p = ht;
	p ++;
	for (int i = 1; i <= n; i ++, p ++) {
		*p = {(unsigned int)(pw_list[i - 1]), 0, 0, 0, (char)ch_list[i - 1]};
//		cout << pw_list[i - 1] << " 0 0 0 " << (char)ch_list[i - 1] << "\n";
	}
	
	for (int i = n + 1; i <= m; i ++, p ++) {
//		auto [w, p, l, r] = ht[i];
		*p = {(unsigned int)(0), 0, 0, 0, '@'};
//		cout << w << " " << p << " " << l << " " << r << "\n";
	}
	
	for (int i = n + 1; i <= m; i ++) {
		select(ht, i - 1);
		ht[s1].parent = i; ht[s2].parent = i;
		ht[i].lchild = s1; ht[i].rchild = s2;
		ht[i].weight = ht[s1].weight + ht[s2].weight;
	}
	
	for (int i = 1; i <= n; i ++) {
		string cd;
		for (int c = i, f = ht[i].parent; f; c = f, f = ht[f].parent) {
			if (ht[f].lchild == c) {
				cd.insert(cd.begin(), '0');
			} else {
				cd.insert(cd.begin(), '1');
			}
			if (power[ht[i].c]) {
				mp[ht[i].c] = cd;
			}
		}
	}
}

void read() {
	ifstream ip_file;
	ip_file.open("resource.txt");
	if (ip_file.is_open()) {
		int is_first = 1;
		string s;
		while (getline(ip_file, s)) {
			if (is_first) {
				is_first = 0;
			} else {
				vs += "\n";
			}
			vs += s;
		}
		cout << "resource.txt读取成功\n";
		ip_file.close();
	} else {
		cout << "无法读取resource.txt\n";
	}
}

void get_cnt() {
	for (auto p : vs) {
		power[p] ++;
	}
	for (auto p : power) {
		ch_list.push_back(p.first);
		pw_list.push_back(p.second);
	}
	n = ch_list.size();
}

void write() {
	ofstream op_file;
	op_file.open("Huffman Code.txt");
	if (op_file.is_open()) {
//		cout << "vs: [" << vs << "]\n\n";
		for (auto p : vs) {
			op_file << mp[p];
		}
		cout << "Huffman Code.txt写入成功\n";
		op_file.close();
	} else {
		cout << "无法保存Huffman编码到硬盘\n";
	}
}

void read_ht() {
	ifstream ip_file;
	ip_file.open("Huffman Code.txt");
	if (ip_file.is_open()) {
		getline(ip_file, vs_ht);
		cout << "Huffman Code.txt读取成功\n";
		ip_file.close();
	} else {
		cout << "无法读取Huffman Code.txt\n";
	}
}

void translate_huffman() {
	int m = vs_ht.size();
//	cout << "m: " << m << "\n";
	for (int i = 0; i <= m - 1; i ++) {
		int ok = 0;
		int l = i, r = i - 1;
		do{
			r ++;
			string sbsr = vs_ht.substr(l, r - l + 1);
//			cout << sbsr << "\n";
			if (mp_ht[sbsr]) {
//				cout << "l: " << l << " ," << "r: " << r << "\n";
				s_trans += char(mp_ht[sbsr]);
				i = r;
				ok = 1;
				break;
			}
		}while (r + 1 <= m - 1);
		if (ok == 0) {
			cout << "解压错误,出现不能解压的编码QAQ\n";
//			cout << "m: " << m << "\n";
//			cout << "l: " << l << "\n";
//			cout << vs_ht.substr(l) << "\n";
			exit(0);
		}
	}
}

void write_ht() {
	ofstream op_file;
	op_file.open("Translated File.txt");
	if (op_file.is_open()) {
		op_file << s_trans;
		cout << "Translated File.txt写入成功\n";
		op_file.close();
	} else {
		cout << "无法保存解压后的文本到硬盘\n";
	}
}

int main() {
	read(); // 读取源文件
//	cout << "源文件内容(vs)[" << vs << "]\n";
	get_cnt();
//	cout << "power: ";
//	for (auto p : power) {
//		cout << "[" << p.first << "]->[" << p.second << "], ";
//	}
//	cout << "\n\n";
//	cout << "ch_list: ";
//	for (auto p : ch_list) {
//		cout << "[" << (char)(p) << "]";
//	}
//	cout << "\n\n";
//	cout << "pw_list: ";
//	for (auto p : pw_list) {
//		cout << "[" << p << "]";
//	}
//	cout << "\n\n";
	
	huffman_tree ht;
	huffman_coding(ht);
	
//	cout << "n: " << n << "\n";
//	cout << "mp.size: " << mp.size() << "\n";
//	for (auto p : mp) {
//		cout << "[" << p.first << "]->[" << p.second << "]\n";
//	}
//	cout << "\n";
	write(); // 写入Huffman编码
	
	read_ht(); // 读取Huffman编码
//	cout << "huff编码[" << vs_ht << "]\n";
	
	for (auto p : mp) {
		mp_ht[p.second] = p.first;
//		cout << "[" <<  p.second << "]<-[" << p.first << "]\n";
	}
//	cout << "\n";
	
	translate_huffman();
	
	write_ht();
	
	return 0;
}
  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
数据结构赫夫曼编码应用实验中,可以采用以下数据结构和流程设计: 1. 数据结构设计: - 频率表:使用哈希表或数组等数据结构来存储字符或符号的频率。 - 赫夫曼树:使用二叉树或优先队列等数据结构来构建赫夫曼树。 - 编码表:使用哈希表或数组等数据结构来存储字符或符号对应的赫夫曼编码。 2. 流程设计: - 读取文件:从文件中读取待压缩或解压缩的数据。 - 构建频率表:遍历读取的数据,统计字符或符号的频率,并存储在频率表中。 - 构建赫夫曼树:根据频率表,使用合适的算法构建赫夫曼树。 - 生成编码表:根据赫夫曼树,通过遍历树节点生成每个字符或符号对应的赫夫曼编码,并存储在编码表中。 - 进行编码压缩:使用生成的编码表,将原始数据进行编码压缩,并生成压缩后的二进制数据。 - 存储压缩数据:将压缩后的二进制数据存储到文件中。 - 进行解码解压:读取压缩数据文件,根据赫夫曼编码表,将压缩数据进行解码解压,恢复原始数据。 - 存储解压数据:将解压后的数据存储到文件中。 - 性能分析:统计压缩前后的文件大小,计算压缩比;分析编码过程的时间复杂度和空间复杂度。 以上是一个基本的数据结构和流程设计,你可以根据具体实验需求进行调整和扩展。例如,可以添加错误处理机制、支持多种文件格式、提供用户界面等。同时,需要注意对数据结构和算法的选择,以保证实验的效率和正确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值