// 包含头文件 #include #include #include #include #include <Windows.h>

using namespace std;

const int N = 127; // 字符集大小

// 定义哈夫曼树结构体 typedef struct { char data; // 存储字符 int weight; // 存储字符出现的次数 int parent, lchild, rchild; // 存储双亲节点、左孩子节点、右孩子节点的下标 } HTNode, *HuffmanTree;

// 定义哈夫曼编码结构体 typedef struct { char data; // 存储字符 string code; // 存储哈夫曼编码 } HCNode, *HuffmanCode;

// 统计字符出现的次数 void frequencyRecord(HuffmanTree& HT) { ifstream originFile('poem.txt'); // 打开文件 if (!originFile) { cout << 'Can't find the file!' << endl; } else { char _data; int frequency[N + 1] = {0}; // 统计字符出现的次数,下标为字符的ASCII码值 while (!originFile.eof()) { // 读取文件内容 if (originFile.get(_data)) { frequency[_data]++; // 统计字符出现的次数 } } originFile.close(); // 关闭文件 HT = new HTNode[2 * N]; // 动态分配内存空间 int k = 0; // 结点下标 for (int i = 0; i <= N; i++) { // 将字符出现次数不为0的加入哈夫曼树 if (frequency[i] != 0) { HT[++k].data = static_cast(i); // 存储字符 HT[k].weight = frequency[i]; // 存储字符出现的次数 } } for (int i = k + 1; i <= 2 * N - 1; i++) { // 将剩余结点初始化 HT[i].weight = HT[i].parent = HT[i].lchild = HT[i].rchild = 0; } for (int i = k + 1; i <= 2 * N - 1; i++) { // 构造哈夫曼树 int s1 = 0, s2 = 0; // s1、s2分别为最小的两个权值 int w1 = INT_MAX, w2 = INT_MAX; // w1、w2分别为最小的两个权值的下标 for (int j = 1; j < i; j++) { // 找出最小的两个权值 if (HT[j].parent == 0) { // 没有父节点 if (HT[j].weight < w1) { w2 = w1, s2 = s1; w1 = HT[j].weight, s1 = j; } else if (HT[j].weight < w2) { w2 = HT[j].weight, s2 = j; } } } 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; // 设置权值 } } }

// 生成哈夫曼编码 void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC) { HC = new HCNode[N + 1]; // 动态分配内存空间 string code; // 存储哈夫曼编码 int child, parent; // child为当前节点的下标,parent为父节点的下标 for (int i = 1; i <= N; i++) { // 生成哈夫曼编码 code = ''; child = i, parent = HT[child].parent; while (parent != 0) { // 从叶子节点开始向上遍历,直到根节点 if (HT[parent].lchild == child) { code = '0' + code; // 左孩子节点编码为0 } else { code = '1' + code; // 右孩子节点编码为1 } child = parent, parent = HT[child].parent; // 更新当前节点和父节点 } HC[i].data = HT[i].data; // 存储字符 HC[i].code = code; // 存储哈夫曼编码 } }

// 将源文件进行哈夫曼编码 void zip(HuffmanTree& HT, HuffmanCode& HC, vector& code) { ofstream codeFile('codefile.txt'); // 打开编码文件 ifstream originFile('poem.txt'); // 打开源文件 if (!codeFile) { cout << 'Can't find the file!' << endl; } else { char _data; cin.unsetf(ios::skipws); while (!originFile.eof()) { // 读取源文件的每个字符 if (originFile.get(_data)) { for (int i = 1; i <= N; ++i) { if (HT[i].data == _data) { // 找到对应的哈夫曼编码 codeFile << HC[i]; // 将哈夫曼编码写入编码文件 code.push_back(HC[i]); // 将哈夫曼编码加入vector中,用于解码 } } } } } codeFile.close(); // 关闭编码文件 }

// 将哈夫曼编码文件进行解码 void unzip(HuffmanTree& HT, HuffmanCode& HC, vector& code) { ofstream decodeFile('decodefile.txt'); // 打开解码文件 if (!decodeFile) { cout << 'Can't find the file!' << endl; } else { vector::iterator v = code.begin(); while (v != code.end()) { // 读取哈夫曼编码 for (int i = 1; i <= N; ++i) { if (HC[i] == *v) { // 找到对应的字符 decodeFile << HT[i].data; // 将字符写入解码文件 } } v++; } } decodeFile.close(); // 关闭解码文件 }

// 将源文件以一个字节进行二进制编码后写入文件 void binaryCode() { ofstream binaryFile('binaryfile.txt'); // 打开二进制编码文件 ifstream originFile('poem.txt'); // 打开源文件 originFile.seekg(0); // 将文件指针移到文件开头 if (!originFile) { cout << 'Can't find the file!' << endl; } else { char _data; cin.unsetf(ios::skipws); while (!originFile.eof()) { // 读取源文件的每个字符 if (originFile.get(_data)) { bitset<8> data(_data); // 将字符转换为8位二进制数 binaryFile << data; // 将二进制数写入二进制编码文件 } } originFile.close(); // 关闭源文件 } }

int main() { system('color 02'); // 设置控制台颜色 cout << '' << endl; cout << '哈夫曼编码解码器' << endl; cout << '' << endl; Sleep(1000); // 等待1秒 HuffmanTree HT; HuffmanCode HC; vector code; cout << '\n\n\n需要进行编码的文件内容为:\n\n'; // 输出原文件内容 system('more poem.txt'); Sleep(2000); // 等待2秒 cout << '\n\n正在打开poem.txt进行二进制编码......' << endl; Sleep(2000); // 等待2秒 binaryCode(); // 将源文件以一个字节进行二进制编码 cout << '\n\n二进制编码内容为:' << endl; Sleep(2000); // 等待2秒 system('more binaryfile.txt'); // 输出二进制编码文件内容 Sleep(2000); // 等待2秒 cout << '\n\n正在统计字符权重......' << endl; Sleep(2000); // 等待2秒 frequencyRecord(HT); // 统计字符出现的次数,并构造哈夫曼树 HuffmanCoding(HT, HC); // 生成哈夫曼编码 cout << '\n\n写入编码文件......' << endl; Sleep(2000); // 等待2秒 zip(HT, HC, code); // 将源文件进行哈夫曼编码,并将哈夫曼编码写入编码文件 cout << '\n\n编码结果为:' << endl; system('more codefile.txt'); // 输出编码文件内容 Sleep(2000); // 等待2秒 cout << '\n\n解码编码文件......' << endl; Sleep(2000); // 等待2秒 unzip(HT, HC, code); // 将哈夫曼编码文件进行解码 cout << '\n\n解码结果为:' << endl; Sleep(2000); // 等待2秒 system('more decodefile.txt'); // 输出解码文件内容 cout << '\n\n编码前占用字节空间:' << endl; Sleep(1000); // 等待1秒 ifstream file_before('binaryfile.txt', ios::binary | ios::ate); auto size_before = file_before.tellg(); // 获取文件大小 cout << size_before << endl; // 输出文件大小 file_before.close(); // 关闭文件 cout << '\n\n编码后占用字节空间:' << endl; Sleep(1000); // 等待1秒 ifstream file_after('codefile.txt', ios::binary | ios::ate); auto size_after = file_after.tellg(); // 获取文件大小 cout << size_after << endl; // 输出文件大小 file_after.close(); // 关闭文件 Sleep(1000); // 等待1秒 cout << '\n\n压缩率为:' << (static_cast(size_before - size_after)) / size_before * 100.0 << '%' << endl; // 计算压缩率并输出 Sleep(100000); // 等待100秒 return 0; }

Huffman 编码解码器:压缩和解压缩文本文件

原文地址: https://www.cveoy.top/t/topic/orfp 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录