要求
两个功能
输入字符串,输出字符串的哈夫曼编码
输入文本文件(英文),输出哈夫曼编码文件
附加:解压缩,即给出哈夫曼编码文件和哈夫曼树,恢复原始字符串文件。
功能一:输入字符串,输出字符串的哈夫曼编码
功能二:输入文本文件(英文),输出哈夫曼编码文件
功能三:解压缩,即给出哈夫曼编码文件和哈夫曼树,恢复原始字符串文件。
代码
// Created by meteor on 2022/4/27.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 128 //ASCII码有128个
#define INF 0x3f3f3f3f
typedef struct {
char c;
unsigned int weight ;
unsigned int parent, lchild, rchild ;
}HTNode, *HuffmanTree; //按照教材定义Huffmantree
typedef char ** HuffmanCode; //Huffman编码表
char appearChar[N + 1]; //出现的字符
unsigned int charIdx[N+1]; //按照ascii值为下标,找在Huffman编码表中的下标
unsigned int charCount[N + 1]; //字符的出现次数,按照ascii值为下标
int cnt = 0; //总共出现的字符数
HuffmanTree HT;
HuffmanCode HC;
void Select(int n, int* s1, int* s2) { //选择最小的两个节点
int min1 = INF; //最小
int min2 = INF; //次小
int x,y,i; //下标
for (i = 1; i <= n; i++) {
if (HT[i].parent == 0) {
if (HT[i].weight <= min1) {
min2 = min1;
min1 = HT[i].weight;
y = x;
x = i;
}else if (HT[i].weight < min2) {
min2 = HT[i].weight;
y = i;
}
}
}
*s1 = x;
*s2 = y;
}
void HuffmanCoding(const int n) {
int m, i, s1=0, s2=0, c, f;
HTNode* p;
char* cd;
if (n <= 1) return;
m = 2 * n - 1;
HT = (HTNode*)malloc((m + 1) * sizeof(HTNode));
//初始化
for (p = HT,i = 1; i <= n; i++) {
p[i].c = appearChar[i];
p[i].weight = charCount[appearChar[i]];p[i].lchild = 0;
p[i].rchild = 0;p[i].parent = 0;
}
for (; i <= m; i++) {
p[i].weight = 0;p[i].lchild = 0;
p[i].rchild = 0;p[i].parent = 0;
}
for (i=n+1; i<=m; ++i) { //建树
Select (i-1, &s1, &s2);
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;
}
HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));
cd = (char*)malloc(n * sizeof(char));
cd[n - 1] = '\0';
for (i = 1; i <= n; i++) {
int start = n - 1;
for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent) {
if (HT[f].lchild == c)
cd[--start] = '0';
else
cd[--start] = '1';
}
HC[i] = (char*)malloc((n - start) * sizeof(char));
strcpy(HC[i], &cd[start]);
}
free(cd);
}
void fun1(){
printf("请输入字符串:\n");
char str[10000];
getchar();
scanf("%[^\n]",str);
for(int i=0;str[i]!=0;i++){
if(charCount[str[i]]==0){
appearChar[++cnt]=str[i];
charIdx[str[i]]=cnt;
}
charCount[str[i]]++;
}
HuffmanCoding(cnt);
printf("构建的的HuffmanTree为:\n");
printf("Leaf Node number:%d\n",cnt);
for(int i=1;i<=cnt;i++){
printf("%d char:%c weight:%d parent:%d Code:%s\n",
i,HT[i].c,HT[i].weight,HT[i].parent,HC[i]);
}
printf("Non-Leaf Nodes:\n");
for(int i=cnt+1;i<=2 * cnt - 1;i++){
printf("%d weight:%d parent:%d lchild:%d rchild:%d\n",
i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
}
printf("\n字符串的Huffman编码为:\n");
int num=0;
for(int i=0;str[i]!=0;i++){
char *tp=HC[charIdx[str[i]]];
for(int j=0;tp[j]!=0;j++){
printf("%c",tp[j]);
num++;
if(num%100==0) puts("");
}
}
}
void fun2(){
char str[10000];
int n = 0;
FILE* fpr, * fpw1, *fpw2;
fpr = fopen("TextFile.txt", "r");//使用相对路径
fpw1 = fopen("hfmTree.txt", "w");//使用相对路径
fpw2 = fopen("CodeFile.txt", "w");//使用相对路径
memset(str,0,sizeof str);
memset(charCount,0,sizeof charCount);
if (fpr == NULL || fpw1 == NULL ||fpw2 == NULL){
printf("没有文件或无法打开文件!");
exit(0);
}
while (!feof(fpr))
{
str[++n] = fgetc(fpr);
if(str[n]==EOF) break;
if(charCount[str[n]]==0){
appearChar[++cnt]=str[n];
charIdx[str[n]]=cnt;
}
charCount[str[n]]++;
}
n--;
fclose(fpr);
HuffmanCoding(cnt);
printf("\n已读入TextFile.txt !\n");
fprintf(fpw1,"Leaf Node number:%d\n",cnt);
for(int i=1;i<=cnt;i++){
fprintf(fpw1,"%d char:%c weight:%d parent:%d Code:%s\n",
i,HT[i].c,HT[i].weight,HT[i].parent,HC[i]);
}
fprintf(fpw1,"Non-Leaf Nodes:\n");
for(int i=cnt+1;i<=2 * cnt - 1;i++){
fprintf(fpw1,"%d weight:%d parent:%d lchild:%d rchild:%d\n",
i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
}
fclose(fpw1);
for(int i=1;str[i]!=EOF;i++){
char *tp=HC[charIdx[str[i]]];
for(int j=0;tp[j]!=0;j++){
fprintf(fpw2,"%c",tp[j]);
}
}
fclose(fpw2);
printf("构建的的HuffmanTree已写入hfmTree.txt中,整个文件的Huffman编码已写入CodeFile.txt中!\n");
}
void fun3(){
char str[80000];
int n = 0,m,idx;
int root,nowNode;
FILE* fpr1, * fpr2, *fpw;
fpr1 = fopen("hfmTree.txt", "r");//使用相对路径
fpr2 = fopen("CodeFile.txt", "r");//使用相对路径
fpw = fopen("decodeFile.txt", "w");//使用相对路径
memset(str,0,sizeof str);
if (fpr1 == NULL || fpr2 == NULL ||fpw == NULL){
printf("没有文件或无法打开文件!");
exit(0);
}
fscanf(fpr1,"Leaf Node number:%d",&n);
m = 2 * n - 1;
HT = (HTNode*)malloc((m + 1) * sizeof(HTNode));
for(int i=1;i<=n;i++){
char temp[10000];
fscanf(fpr1,"%d char:%c weight:%d parent:%d Code:%s\n",
&idx,&HT[i].c,&HT[i].weight,&HT[i].parent,temp);
}
fscanf(fpr1,"Non-Leaf Nodes:\n");
for(int i=n+1;i<=2 * n - 1;i++){
fscanf(fpr1,"%d weight:%d parent:%d lchild:%d rchild:%d\n",
&idx,&HT[i].weight,&HT[i].parent,&HT[i].lchild,&HT[i].rchild);
if(HT[i].parent==0) root = i;
}
idx=0,nowNode=root;
fscanf(fpr2,"%s",str);
for(int i=0;str[i]!=0;i++){
if(str[i]==EOF) break;
if(str[i]=='0'){
nowNode = HT[nowNode].lchild;
}else{
nowNode = HT[nowNode].rchild;
}
if(HT[nowNode].c!=0){
fprintf(fpw,"%c",HT[nowNode].c);
nowNode = root;
}
}
fclose(fpr1);
fclose(fpr2);
fclose(fpw);
printf("解码完成,结果已存入decodeFile.txt中\n");
}
int main(){
int op;
printf("1:输入字符串,输出字符串的哈夫曼编码;\n");
printf("2:输入文本文件(英文),输出哈夫曼编码文件;\n");
printf("3:输入编码后的文件和哈夫曼编码,输出解码后的文件\n");
printf("请输入需要执行功能的序号:");
scanf("%d",&op);
switch (op) {
case 1:
fun1();
break;
case 2:
fun2();
break;
case 3:
fun3();
break;
}
return 0;
}