用哈夫曼树实现的文件压缩与解压,但是解压结果不正确,有人能帮我看看吗

茶韵幽香 2018-05-21 08:03:25
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

struct hnode{
unsigned char name;
unsigned int weight;
};

struct huffnode{
unsigned int weight; //权值
unsigned char name;
int parent, lchild, rchild; //双亲和左右孩子的信息
string code; //哈夫曼编码
};

int m1 = -1;
int m2 = -1;

void select(struct huffnode hf[], int s){ //在s个结点中选择两个权值最小的结点
int i;
unsigned int min1 = 65535; //s个结点中的最小权值
unsigned int min2 = 65535; //s个结点中第二小的权值
for(i=0; i<s; i++){
if(hf[i].parent == -1){
if(hf[i].weight < min1){
min2 = min1;
min1 = hf[i].weight;
m2 = m1;
m1 = i;
}
else if(hf[i].weight < min2){
min2 = hf[i].weight;
m2 = i;
}
}
}
}

void Huffman(struct huffnode hf[], int n){ //构建哈夫曼树
int i;
for(i=0; i<2*n-1; i++){
hf[i].parent = -1;
hf[i].lchild = -1;
hf[i].rchild = -1;
}
for(i=n; i<2*n-1; i++){
select(hf,i);
hf[m1].parent = i;
hf[m2].parent = i;
hf[i].weight = hf[m1].weight+hf[m2].weight;
hf[i].lchild = m1;
hf[i].rchild = m2;
}
}

void HuffmanCode(struct huffnode hf[], int n){ //给每个叶子结点编码
int i;
hf[2*n-2].code = "";
for(i=2*n-2; i>=n; i--){
hf[hf[i].lchild].code = hf[i].code+"0";
hf[hf[i].rchild].code = hf[i].code+"1";
}
}

void compress(struct huffnode hf[], FILE *fp1, FILE *fp2){ //压缩
fseek(fp1, 0, SEEK_SET);
unsigned char ch = fgetc(fp1);
char value = 0;
int size = 0;
unsigned int i;
while(!feof(fp1)){
if(ch == '\r'){
ch = fgetc(fp1);
if(ch == '\n'){
fseek(fp1, -1, SEEK_CUR);
}
}
string str = hf[ch].code;
for(i=0; i<str.size(); i++){
value = value << 1;
if(str[i] == '1')
value = value | 1;
size++;
if(size == 8){
fputc(value, fp2);
value = 0;
size = 0;
}
}
ch = fgetc(fp1);
}
if(size != 0){
value = value << (8-size);
fputc(value, fp2);
}
}

void decompress(struct huffnode hf[], int s, FILE *fp2, FILE *fp3){ //解压
fseek(fp2, 0, SEEK_SET);
int root = 2*s-1;
int m = root;
int index = root-1;
int i;
unsigned char ch = fgetc(fp2);
while(!feof(fp2)){
for(i=0; i<8; i++){
if(ch & 128)
index = hf[index].rchild;
else
index = hf[index].lchild;
if((hf[index].lchild == -1)&&(hf[index].rchild == -1)){
fputc(hf[index].name, fp3);
m--;
if(m == 0)
break;
index = root-1;
}
ch = ch << 1;
}
ch = fgetc(fp2);
}
}

int main()
{
FILE *fp1 = NULL; //文件指针
char filename1[50]; //存放源文件路径
char filename2[50]; //存放压缩文件路径
char filename3[50]; //存放解压文件路径
struct hnode h[256];
struct huffnode hf[600]; //存放哈夫曼树中的结点
int i;
int j = 0;
int n = 0; //哈夫曼树中叶子结点的数目
cout << "请输入源文件路径:" << endl;
cin >> filename1;
if((fp1 = fopen(filename1, "rb")) == NULL){
cout << "打开文件失败!" << endl;
return -1;
}
for(i=0; i<256; i++){
h[i].weight = 0;
}
unsigned char ch = fgetc(fp1);
while(!feof(fp1)){
if(ch == '\r'){
ch = fgetc(fp1);
if(ch == '\n'){
fseek(fp1, -1, SEEK_CUR);
}
}
h[ch].weight++;
h[ch].name = ch;
ch = fgetc(fp1);
}
for(i=0; i<256; i++){
if(h[i].weight != 0){
hf[j].weight = h[i].weight;
hf[j].name = h[i].name;
j++;
n++;
}
}
Huffman(hf, n);
HuffmanCode(hf, n);

cout << "请输入压缩文件路径:" << endl;
cin >> filename2;
FILE *fp2 = fopen(filename2, "wb");
compress(hf, fp1, fp2);
cout << "请输入解压文件路径:" << endl;
cin >> filename3;
FILE *fp3 = fopen(filename3, "wb");
fp2 = fopen(filename2, "rb");
decompress(hf, n, fp2, fp3);

fclose(fp1);
fclose(fp2);
fclose(fp3);
return 0;
}
...全文
943 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
donjin9 2018-05-23
  • 打赏
  • 举报
回复
compress里面的string str = hf[ch].code;这个hf和h感觉弄混了吧。\r\n为啥不一起编码呢。
赵4老师 2018-05-22
  • 打赏
  • 举报
回复
代码功能归根结底不是别人帮自己看或讲解或注释出来的;而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒:再牛×的老师也无法代替学生自己领悟和上厕所! 单步调试和设断点调试(VS IDE中编译连接通过以后,按F10或F11键单步执行,按Shift+F11退出当前函数;在某行按F9设断点后按F5执行停在该断点处。)是程序员必须掌握的技能之一。
赵4老师 2018-05-22
  • 打赏
  • 举报
回复
百度搜相关关键字。 电脑内存或文件内容或传输内容只是一个一维二进制字节数组及其对应的二进制地址; 人脑才将电脑内存或文件内容或传输内容中的这个一维二进制字节数组及其对应的二进制地址的某些部分看成是整数、有符号数/无符号数、浮点数、复数、英文字母、阿拉伯数字、中文/韩文/法文……字符/字符串、汇编指令、函数、函数参数、堆、栈、数组、指针、数组指针、指针数组、数组的数组、指针的指针、二维数组、字符点阵、字符笔画的坐标、黑白二值图片、灰度图片、彩色图片、录音、视频、指纹信息、身份证信息…… 推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。
茶韵幽香 2018-05-21
  • 打赏
  • 举报
回复

64,676

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧