对小甲鱼哈弗曼树代码的小修改

只是记录一下自己写作业的过程,我不是一个程序员,我是一个想进德云社的闲散人员
一.自己对huffman树的理解
先用程序读入一篇或多篇英文文章,把文章中出现的每一个字符都当做树结构中的一个节点,并且给每个节点附上一个权值(该字符在文章中出现的次数),通过这些权值,构成最小生成树。这就是huffman树的建立过程。最小生成树建立好以后,每个字符都会有一个由二进制数构成的编码,可以根据这些编码对一串二进制树解码,把二进制数还原成字符。具体内容会在程序中讲解。

二.程序讲解

# include <stdio.h>
# include <stdlib.h>
# include "huffman.h"

int main()
{
    char *rf = read_file("1.txt");//读入文档内容
    htTree * codeTree = buildTree(rf);//建立huffman树
    hlTable *codeTable = buildTable(codeTree);//建立编码表
    char *enco = read_file("encode.txt");
    char* deco = encode(codeTable,enco);//对读入字符串编码
    decode(codeTree,deco);对读入字符串解码
    return 0;
}

1.read_file函数讲解
上面已经提到过huffman就是通过读入一写字符,根据每个字符的出现次数生成最小生成树,那么如何读入字符内容呢。我选择从txt文档里读入。先看一下这个函数的代码吧

char* read_file(char *fname)
{
    FILE*fp = fopen(fname,"rb");
    char arr[100][256];
    char *str;
    int len=0;
    int i=0;
    while(fgets(arr[i],256,fp)!=NULL)
      {
           i++;
      }
    fclose(fp);
    str = (char*)malloc(sizeof(char)*256*(i));
    memset(str,0,sizeof(char)*256*(i));
    for(int j=1;j<=i;j++)
    {
        strcat(str,arr[j-1]);
    }
    return str;
}

这里需要思考的一个问题是如何读入多行文档。用fgets函数可以很好解决。根据我个人了解,fgets函数每次都能读入一行文档,如果文档有多行,再次使用fgets函数读取文档时,就会读取下一行。直到 fgets(arr[i],256,fp)!=NULL的时候,说明多行文档已经读入完毕。每次读取一行内容的时候都会存到二维数组arr中。fgets函数会自动在第一个参数数组的末尾加上结束符’\0’.
于此同时通过i++,来得到当行文档总共有多少行。一次来获得要存入全部文档总共需要的一个大概内存。(char*)malloc(sizeof(char)256(i)),假设每行有256个字符,在这里肯定会浪费一些空间,这里就留给你们去修改。然后通过memset初始化字符串空间。
然后吧文档的每行内容存到str指向的空间。这样就完成了对当行字符的读入并用一个指针指向这些字符内容,并返回。

2.buildTree函数内容讲解

htTree * buildTree(char *inputString)//建立Huffman树
{

        int *probablity = (int*)malloc(sizeof(int)*256);//整数数组
    for(int i=0;i<256;i++)
    {
        probablity[i]=0;//整数数组初始化
    }
    for(int j=0;inputString[j]!='\0';j++)
    {
        probablity[(unsigned int)inputString[j]]++;//当读入的字符串不结束时,一直循环,对应ascall编码的整数下标的数组元素+1
    }//出现次数用作权值

    pQueue * huffmanqueue = NULL; 
    huffmanqueue = iniPQueue(huffmanqueue);//生成并初始化huffamn树队列

    for(int k=0;k<256;k++)
    {
        
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
#include <stdio.h> #define MAXBIT 2000 /*定义哈夫曼编码的最大长度*/ #define MAXVALUE 1000 /*定义最大权值*/ #define MAXLEAF 256 /*定义哈夫曼中最多叶子节点个数*/ #define MAXNODE MAXLEAF*2-1 /*哈夫曼最多结点数*/ typedef struct { /*哈夫曼编码结信息的构*/ char bit[MAXBIT]; int start; }Hcodetype; typedef struct { /*哈夫曼结点的结构*/ int weight; int parent; int lchild; int rchild; char ch; }Hnodetype; char ch[MAXVALUE*5]; static int numbers; int number=0; char varyCh[MAXLEAF]; int weight[MAXLEAF]; int pos[256]; int root; char allHc[MAXVALUE*20]; /*----------分析输入的字符串--------------*/ void analyze(char ch[],int numbers,char varyCh[],int weight[],int& number){ int temp[256]={0}; int n=0; for(int i=0;i<numbers;i++){ temp[(int)ch[i]]++; } for(int j=0;j<256;j++){ if(temp[j]!=0){ varyCh[n]=(char)j; weight[n]=temp[j]; pos[j]=n; n++; } } number=n; } void huffmantree(Hnodetype huffnode[MAXNODE]) /*构造哈夫曼的函数*/ { int i,j,m1,m2,x1,x2; analyze(ch,numbers, varyCh, weight,number); for(i=0;i<number;i++) /*存放哈夫曼结点的数组huffnode[]初始化*/ { huffnode[i].weight=weight[i]; huffnode[i].parent=-1; huffnode[i].lchild=-1; huffnode[i].rchild=-1; huffnode[i].ch=varyCh[i]; } for(i;i<2*number;i++){ huffnode[i].weight=0; huffnode[i].parent=-1; huffnode[i].lchild=-1; huffnode[i].rchild=-1; } /* for(i=0;i<n;i++) /*输入入N个叶子节点的权值 { printf("please input %d character's weight\n",i); scanf("%d",&huffnode[i].weight); } */ for(i=0;i<number-1;i++){/*开始循环构造哈夫曼*/ m1=m2=MAXVALUE; //m1拥有最小值 x1=x2=0; //记录一次循环后找到最小和次小节点的位置 for(j=0;j<number+i;j++){ if(huffnode[j].weight<m1&&huffnode[j].parent==-1) { m2=m1;x2=x1;m1=huffnode[j].weight;x1=j; } else if(huffnode[j].weight<m2&&huffnode[j].parent==-1) { m2=huffnode[j].weight;x2=j; } } huffnode[x1].parent=number+i; huffnode[x2].parent=number+i; huffnode[number+i].weight=huffnode[x1].weight+huffnode[x2].weight; huffnode[number+i].lchild=x1; huffnode[number+i].rchild=x2; } } void unhanffman(Hnodetype huffnode[]){ //根据哈夫曼和所有字符的编码进行译码 int i=0; int r=root; //指向根节点 while((allHc[i]!=NULL)){ if(allHc[i]=='0')r=huffnode[r].lchild; else r=huffnode[r].rchild; if(huffnode[r].lchild==-1&&huffnode[r].rchild==-1) { printf("%c",huffnode[r].ch); r=root; } i++; } printf("\n\n"); } void main() { Hnodetype huffnode[MAXNODE]; Hcodetype leafcode[MAXLEAF],cd; int i,j,c,p,num=0,posite,allhc=0; char temp; printf(" 赫夫曼编码的应用 \n\n"); printf(" ○○○○○○○○○○○○○○○○○○○○○○○○○ "); printf("\n\n"); printf(" ●请输入字符串并以#号结束"); //scanf("%d",&n); /*输入叶子节点个数*/ /*----------循环接受字符-------------------*/ while((ch[num]=getchar())!='#'){ num++; } numbers=num; //得到字符个数----------------- huffmantree(huffnode); /*建立哈夫曼*/ FILE *fp; if(!(fp=fopen("D:\\text1.txt","w"))) { printf("文件打开失败!"); } for(i=0;i<number;i++) /*该循环求每个叶子节点对应字符的哈夫曼编码*/ { cd.start=number-1;c=i; p=huffnode[c].parent; while(p!=-1) //逆向求叶子节点哈夫曼编码左0右1 { if(huffnode[p].lchild==c) cd.bit[cd.start]='0'; else cd.bit[cd.start]='1'; cd.start--;c=p; p=huffnode[c].parent; root=c; } //循环结束p指向根节点 for(j=cd.start+1;j<number;j++) /*保存求出的每个叶节点的哈夫曼编码编码的起始位*/ { leafcode[i].bit[j]=cd.bit[j]; fputc(leafcode[i].bit[j],fp); } leafcode[i].start=cd.start; //leafcode[i].ch=huffnode[i].ch; } printf("\n"); printf(" --------------------------------------------------------------- \n"); printf("\n"); for(i=0;i<number;i++) /*输出每个叶子节点的哈夫曼编码*/ { printf(" ☆字符:%c",huffnode[i].ch); printf(" 次数:%d",huffnode[i].weight); printf("\n"); printf(" ★'%c'字符的编码是:",huffnode[i].ch); for(j=leafcode[i].start+1;j<number;j++) printf("%c",leafcode[i].bit[j]); printf("\n"); } fclose(fp); printf("\n"); printf(" --------------------------------------------------------------- \n"); printf("\n"); printf(" ☆字符串被编码成为:"); if(!(fp=fopen("D:\\text1.txt","r"))) { printf("文件打开失败!"); } for(i=0;i<numbers;i++) /*所有字符的哈夫曼编码*/ { temp=ch[i]; posite=pos[(int)temp]; for(j=leafcode[posite].start+1;j<number;j++) { printf("%c",leafcode[posite].bit[j]); allHc[allhc]=leafcode[posite].bit[j]; allhc++; } } printf("\n\n"); printf(" --------------------------------------------------------------- \n"); printf("\n"); printf(" ★译码的结果如下:"); unhanffman(huffnode); fclose(fp); }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值