64,676
社区成员
发帖
与我相关
我的任务
分享
#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;
}