数据结构实验6:哈夫曼编码实现文本压缩

要求

两个功能
输入字符串,输出字符串的哈夫曼编码
输入文本文件(英文),输出哈夫曼编码文件
附加:解压缩,即给出哈夫曼编码文件和哈夫曼树,恢复原始字符串文件。

功能一:输入字符串,输出字符串的哈夫曼编码

功能二:输入文本文件(英文),输出哈夫曼编码文件

功能三:解压缩,即给出哈夫曼编码文件和哈夫曼树,恢复原始字符串文件。

代码

// 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;
}

  • 2
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值