C语言读取TXT中文件并对其中字符进行赫夫曼编码

---恢复内容开始---

赫夫曼编码为文件压缩的重要部分。

这次的代码是在文件“in.txt”中读取其中的字符串,并对其进行赫夫曼编码。

操作者可以对in.txt进行更改,输出会显示每个字符在文本中的个数,并可以输入你想要查找的字符,得到在本文中的赫夫曼编码。

先说一下这次代码的几点不足:

首先这次的存储空间为静态,全文没有malloc,而是固定的数组100,因此在txt中的字符串长度不要超过100,也不要小于3;

其次赫夫曼树的存储结构为结构体数组形式,没有用指针(链式)存储;

再有赫夫曼树构造时的权值为个数,而不是该字符在全文中所占的比例。

这几点不足主要是因为这样比较简单。。。

上代码

#include <stdio.h>
#include <string.h>
static int length=0;
static int tree_length;
struct per
{
    char let;
    int num=0;
} per[100];//每个字符为一个per,let为其字符名称,num为其在文中的个数
struct tree
{
    int weight;
    int lchild=-1,rchild=-1,parent=100;
    char letter='<';
    char code='x';
} tree[200];//赫夫曼树结构体,几个字母都是默认值,都是随便取得
void getpercentage(char l[])//得到每个字符在文本中的个数
{
    for(int i=0; i<strlen(l); i++)//获得个数
    {
        if(l[i]!='<')
        {
            per[length].let=l[i];
            per[length].num=1;
            for(int j=i+1; j<strlen(l); j++)
                if(l[i]==l[j])
                {
                    per[length].num++;
                    l[j]='<';
                }
            length++;
        }
    }
}
void gethuffmantree(char l[])//构造赫夫曼树
{
    for(int i=0; i<length-1; i++)//先进行从小到大的排序
        for(int j=0; j<length-i-1; j++)
            if(per[j].num>per[j+1].num)
            {
                per[100]=per[j];
                per[j]=per[j+1];
                per[j+1]=per[100];
            }
    for(int i=0; i<length; i++)
        printf("%c %d\n",per[i].let,per[i].num);//按从小到大的顺序输出
    //
    tree[0].weight=per[0].num;
    tree[1].weight=per[1].num;
    tree[2].lchild=0;
    tree[2].rchild=1;
    tree[0].parent=2;
    tree[1].parent=2;
    tree[0].letter=per[0].let;
    tree[1].letter=per[1].let;
    tree[2].weight=per[0].num+per[1].num;
    int tempw=tree[2].weight;
    int temp=2;
    //先用最小的两个构造一个树,temp为构造到的结点的编号,tempw为顶部结点(即当前最大的那个)的权值
    for(int i=2; i<strlen(l)-1&&per[i].num!=0; i++)
    {
        if((per[i].num<tempw&&per[i+1].num<tempw)&&(per[i+1].num!=0))
        {
            //
            temp=temp+4;
            tree[temp-1].lchild=temp-3;
            tree[temp-1].rchild=temp-2;
            tree[temp-3].letter=per[i].let;
            tree[temp-2].letter=per[i+1].let;
            tree[temp-3].weight=per[i].num;
            tree[temp-2].weight=per[i+1].num;
            tree[temp-1].weight=tree[temp-2].weight+tree[temp-3].weight;
            tree[temp-3].parent=temp-1;
            tree[temp-2].parent=temp-1;
            tree[temp].lchild=temp-4;
            tree[temp].rchild=temp-1;
            tree[temp].weight=tree[tree[temp].lchild].weight+tree[tree[temp].rchild].weight;
            tree[temp-4].parent=temp;
            tree[temp-1].parent=temp;
            i++;
            tempw=tree[temp].weight;
        }
        //分为两种情况,上面的为在一旁构建新树的情况,要用两个per
        //下面的为用一个per继续生长的情况
        else
        {

            temp=temp+2;
            tree[temp].lchild=temp-2;
            tree[temp].rchild=temp-1;
            tree[temp-1].parent=temp;
            tree[temp-2].parent=temp;
            tree[temp-1].weight=per[i].num;
            tree[temp-1].letter=per[i].let;
            tree[temp].weight=tree[tree[temp].lchild].weight+tree[tree[temp].rchild].weight;
            tempw=tree[temp].weight;

        }
    }
    tree_length=temp+1;
}
void getcode(int t)//得到每个结点的编码,即‘0’或‘1’,并将其写入结构体数组中
{
    if(t==-1)
        return;
    else
    {
        tree[tree[t].lchild].code='0';
        tree[tree[t].rchild].code='1';
        getcode(t-1);
    }
}
void findcode(int w)//得到想要的赫夫曼编码,并将其输出
{
    int p;
    char code[20];
    int code_length=0;
    for(int i=0; i<tree_length; i++)
        if(tree[i].letter==w)
        {
            p=i;
            code[0]=tree[i].code;
            break;
        }
    for(int j=1; p<tree_length; j++)
    {
        code[j]=tree[tree[p].parent].code;
        p=tree[p].parent;
        code_length++;
    }//方法为从要查找节点开始,找他的父节点,并记录编码值,最后将其倒序输出
    for(int i=code_length-2; i>=0; i--)
        printf("%c",code[i]);
    printf("\n");
}
int main()
{
    char letter[100];
    //
    FILE *fp=fopen("in.txt","r");
    if(!fp)
    {
        printf("can't open file\n");
        return -1;
    }
    fgets(letter,100,fp);
    fclose(fp);
    //打开文件部分
    getpercentage(letter);
    gethuffmantree(letter);
    getcode(tree_length-1);
    char want;
    printf("Please enter the letter you want to find,and end with 'EOF':\n");
    while(scanf("%c",&want)!=EOF)
        findcode(want);
}

 样例

欢迎大家指正和教导!!!

 

---恢复内容结束---

转载于:https://www.cnblogs.com/superxinyu/p/6308409.html

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值