基于哈夫曼编码对txt文档实现压缩处理 | 算法分析之贪心算法设计 C语言版

声明:凡代码问题,欢迎在评论区沟通。承蒙指正,一起成长!

 

目录

一、实验内容与要求

二、概要设计 

三、直接上代码  

四、运行结果 


一、实验内容与要求

内容:哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。
给出现频率高的字符较短的编码,出现频率较低的字符以较长的编码,可以大大缩短总码长。哈夫曼提出构造最优前缀码的贪心算法,由此产生的编码方案称为哈夫曼编码。哈夫曼算法以自底向上的方式构造表示最优前缀码的二叉树T。此算法以|c|个叶结点开始,执行|c|-1次的“合并”运算后产生最终所要求的树T。
要求:随机输入超过10字符及其频度,求出其这些字符的哈夫曼编码。 

二、概要设计 

1.定义哈夫曼树结点结构体类型;
2.以只读方式打开同文件夹下的“example.txt”,用指针申请动态字符数组tmp,并将文本读到字符串中;
3.哈夫曼树建立函数CrtHuffmanTree流程,(1)初始化:由给定的n个权值构造n棵只有一个根结点的二叉树,从而得到一个森林F;(2)选取与合并:利用select函数在F中选取根结点的权值最小的两棵二叉树分别作左、右子树构造一棵新的二叉树,这棵新的二叉树的根结点的主值为其左、右子树根结点的权值之和;(3)删除与并入:在集合F中删除作为左、右子树的两棵二叉树,并将新的二叉树加入到集合F中;(4)重复(2)、(3)两步,直到集合F中只剩下一棵二叉树时,便生成哈夫曼树;
4.哈夫曼编码建立函数CrtHutimanCode流程,(1)从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码;(2)分配求当前编码的工作空间,从右向左逐位存放编码;(3)求n个叶子结点对应的哈夫曼编码:初始化编码起始指针,从叶子结点开始向上倒推,左分支为0,右分支为1,向上倒推;(4)为编码分配空间,把编码cd[]复制到hc[i]中;
5.打印出26个字母在文本中出现的频度及编码,最后以哈夫曼编码形式打印出“example.txt”文本包括26个小写字母字符;

三、直接上代码  

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MaxLeaf  26
#define MaxNode MaxLeaf*2-1
#define Maxbit  100

typedef struct
{
    int weight;
    int parent;
    int LChild;
    int RChild;
} HTNode,HuffmanTree[MaxLeaf+1]; //结点结构体
typedef char * HuffmanCode[MaxLeaf+1];

void CrtHuffmanTree(HuffmanTree ht,int w[],int n);//函数声明:建立哈夫曼树
void select(HuffmanTree ht,int n,int*x,int*y);//函数声明:寻找权值最小节点
void CrtHutimanCode(HuffmanTree ht,HuffmanCode hc,int n);//函数声明:生成哈夫曼编码
HuffmanTree ht;//树结点
HuffmanCode hc;//编码
int fre[MaxLeaf+1]= {0};
int main()
{
    int i;
    char name[20];
    printf("Please enter your File's name:");
    scanf("%s",&name);
    FILE *fp=fopen(name,"r");
    fseek(fp, 0, SEEK_END);
    int fileLen = ftell(fp);
    char *tmp = (char *) malloc(sizeof(char) * fileLen);
    fseek(fp, 0, SEEK_SET);
    fread(tmp, fileLen, sizeof(char), fp);
    fclose(fp);
    for(i = 0; i < fileLen-5; ++i)
    {
        if((97<=tmp[i]<=122)&&tmp[i]!='.'&&tmp[i]!=','&&tmp[i]!=' '&&tmp[i]!='\n'&&tmp[i]!=':')
            fre[tmp[i]-96]+=1;
    }
    CrtHuffmanTree(ht,fre,MaxLeaf);
    CrtHutimanCode(ht,hc,MaxLeaf);
    printf("字符\t频度\t编码\n");
    for(i = 1; i <=26; ++i)
        printf("%c:\t%d\t%s\n",96+i,fre[i],hc[i]);
    printf("\nTXT文本的哈夫曼编码:\n");
    for(i = 0; i < fileLen-4; ++i)
    {
        if((97<=tmp[i]<=122)&&tmp[i]!='.'&&tmp[i]!=','&&tmp[i]!=' '&&tmp[i]!='\n'&&tmp[i]!=':')
            printf("%s",hc[tmp[i]-96]);
        if(tmp[i]=='\n'||tmp[i]==' ')
            printf(" ");
        if(i!=0&&i%30==0)
            printf("\n");
    }
    printf("\n\n");/*
    for(i = 1; i <=MaxNode; ++i){
        printf("%d %d %d %d\t",ht[i].weight,ht[i].parent,ht[i].LChild,ht[i].RChild);
        if(i%3==0)
            printf("\n");
    }*/

    return 0;
}
void select(HuffmanTree ht,int n,int*x,int*y)
{
    int j,min1=2021,min2=2021;
    for(j=1; j<=n; j++)
        if((ht[j].parent==0)&(ht[j].weight<min1))/*找到第一个权值最小的根结点*/
        {
            min1=ht[j].weight;
            *x=j;
        }/*返回此结点的位置*/
    for(j=1; j<=n; j++)
        if(j!=*x&&ht[j].weight<min2&&ht[j].parent==0)/*找到第二个权值最小的根结点*/
        {
            min2=ht[j].weight;
            *y=j;
        }/*返回此结点的位置*/
}
void CrtHuffmanTree(HuffmanTree ht,int w[],int n)
{
    int i,s1,s2;
    for(i=1; i<=n; i++)
    {
        ht[i].weight= w[i];
        ht[i].parent = 0;
        ht[i].LChild = 0;
        ht[i].RChild = 0;
    }
    int m=2*n-1;
    for(i=n+1; i<=m; i++)
    {
        ht[i].weight= 0;
        ht[i].parent = 0;
        ht[i].LChild = 0;
        ht[i].RChild = 0;
    }
    for(i=n+1; i<=m; i++) /*创建非叶结点,建哈夫曼树*/
    {
        select(ht,i-1,&s1,&s2);
        ht[i].weight=ht[s1].weight+ht[s2].weight;
        ht[s1].parent=i;
        ht[s2].parent=i;
        ht[i].LChild=s1;
        ht[i].RChild=s2;
    }/*哈夫曼树建立完毕*/
}
void CrtHutimanCode(HuffmanTree ht,HuffmanCode hc,int n)
{
    /*从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码*/
    char *cd;
    int i;
    cd=(char*)malloc(n*sizeof(char));
    cd[n-1]='\0';
    for(i=1; i<=n; i++)
    {
        int start=n-1,c=i;
        int p=ht[i].parent;
        while(p!=0)
        {
            /*从叶子结点开始向上倒推*/
            --start;
            if(ht[p].LChild==c) cd[start]='0';/*左分支标0*/
            else cd[start]='1';/*右分支标1*/
            c=p; p=ht[p].parent; /*向上倒推*/
        }
        hc[i]=(char*)malloc((n-start)*sizeof(char));/*为第1个编码分配空间*/
        strcpy(hc[i],&cd[start]);
    }
    free(cd);
}

四、运行结果 

 运行结果截图:

文本example.txt截图:

 Huffman结构截图:

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尘封的CPU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值