1、创建工程。
2、读取源文件。
3、生成哈夫曼树。
4、生成哈夫曼编码。
5、压缩原文件。
6、保存压缩文件。
7、扩展功能。
实验代码参考:https://blog.csdn.net/cxh_1231/article/details/80530668
main.cpp
主函数
#include "iostream"
#include "file.h"
#include"HuffmanTree.h"
using namespace std;
int main() {
cout << "请输入文件名:";
char filename[256];
cin >> filename;
if (Compress(filename) == 1) {
cout << "\n压缩完成!" << endl;
}
else cout << "\n压缩失败!" << endl;
return 0;
}
HuffmanTree.h
哈夫曼树头文件
#ifndef HuffmanTree_H
#define HuffmanTree_H
#include
typedef struct HuffmanTree
{
int weight;
int id;
struct HuffmanTree* lchild;
struct HuffmanTree* rchild;
int num[50];
}HuffmanNode;
HuffmanNode* createHuffmanTree(int* a, int n);
void HuffmanCode(HuffmanNode* hufmTree, int depth,long long &sum);
void PHuffmanCode(HuffmanNode* hufmTree, int depth, int id, char *p);
#endif
HuffmanTree.cpp
哈夫曼树源文件
#include"HuffmanTree.h"
#include"stdio.h"
#include"stdlib.h"
HuffmanNode* createHuffmanTree(int* a, int n)
{
int i, j;
HuffmanNode **temp, *hufmTree = NULL;
temp = (HuffmanNode**)malloc(n * sizeof(HuffmanNode));
for (i = 0; i < n; ++i) {
temp[i] = (HuffmanNode*)malloc(sizeof(HuffmanNode));
temp[i]->weight = a[i];
temp[i]->id = i;
temp[i]->lchild = temp[i]->rchild = NULL;
}
for (i = 0; i < n - 1; ++i) {
int small1 = -1, small2;
for (j = 0; j < n; ++j) {
if (temp[j] != NULL && small1 == -1) {
small1 = j;
continue;
}
else if (temp[j] != NULL) {
small2 = j;
break;
}
}
for (j = small2; j < n; ++j) {
if (temp[j] != NULL) {
if (temp[j]->weight < temp[small1]->weight) {
small2 = small1;
small1 = j;
}
else if (temp[j]->weight < temp[small2]->weight) {
small2 = j;
}
}
}
hufmTree = (HuffmanNode*)malloc(sizeof(HuffmanNode));
hufmTree->weight = temp[small1]->weight + temp[small2]->weight;
hufmTree->lchild = temp[small1];
hufmTree->rchild = temp[small2];
temp[small1] = hufmTree;
temp[small2] = NULL;
}
free(temp);
return hufmTree;
}
void HuffmanCode(HuffmanNode* hufmTree, int depth,long long &sum) {
static int code[20];
if (hufmTree) {
if (hufmTree->lchild == NULL && hufmTree->rchild == NULL) {
printf("id为%d权值为%d的叶子结点的哈夫曼编码为 ", hufmTree->id, hufmTree->weight);
int i;
sum += depth * hufmTree->weight;
for (i = 0; i < depth; ++i) {
printf("%d", code[i]);
}
printf("\n");
}
else {
code[depth] = 0;
HuffmanCode(hufmTree->lchild, depth + 1, sum);
code[depth] = 1;
HuffmanCode(hufmTree->rchild, depth + 1, sum);
}
}
}
void PHuffmanCode(HuffmanNode* hufmTree, int depth,int id,char *p) {
static int code[20];
if (hufmTree) {
if (hufmTree->id==id) {
int i;
for (i = 0; i < depth; ++i) {
p[i] = code[i];
}
return;
}
else {
code[depth] = 0;
PHuffmanCode(hufmTree->lchild, depth + 1, id,p);
code[depth] = 1;
PHuffmanCode(hufmTree->rchild, depth + 1, id,p);
}
}
}
file.h
文件头文件
#ifndef File_H
#define File_H
int Compress(const char *pFilename);
char Str2byte(const char *p);
#endif
file.cpp
文件源文件
#define _CRT_SECURE_NO_WARNINGS//消除scanf警告
#include"file.h"
#include"HuffmanTree.h"
#include"stdlib.h"
#include"iostream"
using namespace std;
int Compress(const char *pFilename) {
int weight[256] = { 0 };
FILE *in = fopen(pFilename, "rb");
int temp;
long long length=0;
while ((temp = getc(in)) != EOF) {
weight[temp]++;
length++;
}
fclose(in);
cout << "显示256种字节出现的次数:" << endl;
cout << "Byte\t" << "Weight" << endl;
for (int i = 0; i < 256; i++) {
printf("0x%02X\t%d\n", i, weight[i]);
}
long long sum = 0;
HuffmanTree *HT=createHuffmanTree(weight, 256);
HuffmanCode(HT, 0, sum);
int left = sum % 8;
sum = left ? sum / 8 + 1 : sum;
char *Buffer = (char*)malloc(sizeof(char)*sum);
char filename[256] = { 0 };
strcpy(filename, pFilename);
strcat(filename, ".temp");
FILE *out = fopen(filename, "wb");
FILE *in2 = fopen(pFilename, "rb");
int pos = 0;
char ch[50] = { 0 };
char cd[256] = { 0 };
for (int i = 0; i < length; i++) {
temp = getc(in);
PHuffmanCode(HT, 0, temp, ch);
strcat(cd, ch);
while (strlen(cd) >= 8) {
Buffer[pos++] = Str2byte(cd);
for (int i = 0; i < 248; i++) cd[i] = cd[i + 8];
}
}
if (strlen(cd) > 0) {
Buffer[pos++] = Str2byte(cd);
}
for (int i = 0; i < strlen(Buffer); i++) {
fputc(Buffer[i], out);
}
fclose(in2);
fclose(out);
cout << "目标文件大小:" << length << "字节" << endl;
cout << "压缩文件大小:" << sum << "字节" << endl;
cout << "压缩比率:" << (double)sum * 100 / length << "%" << endl;
system("pause");
return 1;
}
char Str2byte(const char *p) {
char b = 0x00;
for (int i = 0; i < 8; i++) {
b = b << 1;
if (p[i] == '1') {
b = b | 0x01;
}
}
return b;
}