哈夫曼树实验报告(付原C语言程序)

哈夫曼树实验报告(付原C语言程序)
哈夫曼树实验报告(付原C语言程序)

哈夫曼树实验报告

需求分析:

从终端读入一串字符,利用建立好的哈夫曼树对其进行编码,储存到文件当中去,然后从文件读入哈夫曼编码,针对每个字母对其进行译码,翻译为原来的信息。

二、概要设计

程序分为以下几个模块:

1、从终端读入字符集大小,n个字符和n个权值,建立哈夫曼树,写入文件hfmTree中去。

2、对hfmTree进行编码,建立hfm编码表。

3、从文件ToTran读入信息,根据hfm编码表对其进行hfm编码,将编码后的信息写入文件Codefile 中去

4、对Codefile文件反向译码,结果储存在Textfile中去。

5、将建立的hfmTree打印在终端上,并储存于相应的Treeprint文件中去。

抽象的数据定义如下:

哈夫曼树结构

typedef struct //定义哈夫曼树的结构

{

int weight; //权值

int parent; //双亲

int lchild; //左孩子

int rchild; //右孩子

}htnode,huffmantree[M+1];

建立哈夫曼树

void crthuffmantree(huffmantree ht,int w[],int n) //初始化哈夫曼树

{

int i,s1,s2,m;

for(i=1;i<=n;i++)

{

ht[i].weight=w[i];

ht[i].parent=0;

ht[i].lchild=0;

ht[i].rchild=0;

}

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[i].lchild=s1;

ht[i].rchild=s2;

}

}

typedef char *huffmancode[N+1]; //建立哈夫曼树编码表

void crthuffmancode(huffmantree ht,huffmancode hc,int n)

{

char *cd; //新建立一个指针

int start,i,c,p;

cd=(char*)malloc(n*sizeof(char));//分配求一个字符的哈夫曼编码的空间

cd[n-1]='\0'; //编码结束符

for(i=1;i<=n;i++)

{

start=n-1;

c=i;

p=ht[i].parent;

while(p!=0)

{

--start;

if(ht[p].lchild==c)

cd[start]='0';

else

cd[start]='1';

c=p;

p=ht[p].parent;

}

hc[i]=(char *)malloc((n-start)*sizeof(char));

strcpy(hc[i],&cd[start]);

}

free(cd);

}

select(huffmantree ht,int pos,int *s1,int *s2) //取最小和次小权值

{

int j,m1,m2;

m1=m2=maxint;

for(j=1;j<=pos;j++)

{

if(ht[j].weight

{

m2=m1;

*s2=*s1;

*s1=j;

m1=ht[j].weight;

}

else if(ht[j].weight

{

m2=ht[j].weight;

}

}

}

主程序模块

int main()

{

初始化参数

printf("请输入:初始化 I;编码 E;译码 D;印代码文件 P;印哈弗曼树 T\n");

printf("结束请输入Q\n");

while(1)

{ //这就是用户输入

scanf("%c",&q);

if(q=='Q')

{

break;

}

if(q=='I')

{

fpw=fopen("hfmtree.txt","w");

ftest=fopen("date.txt","r");

printf("请输入密码表,第一位表示密码表大小,之后按空格键开始以紧凑的格式输入编码字母和权值。\n");

scanf("%d",&n); //字符集大小输入

getchar(); //吃空格用的

for(i=1;i<=n;i++) //这里本来是要在终端输入的,我为了图个测试方便就写文件里,可以自己改回来

{

fscanf(ftest,"%c",&a);

if(a!='\n')

{

str[i]=a;

fscanf(ftest,"%d",&weight[i]);

}

else i--; //减去回车键的计数,应该是用于输入量过多情况下需要隔行输入的设定

}

for(i=n+1;i<=2*n-1;i++) //补全剩余的

{

str[i]='0';

}

crthuffmantree(ht1,weight,n); //建立哈夫曼树

crthuffmancode(ht1,hc1,n); //建立哈夫曼编码表

for(i=1;i<=2*n-1;i++) //打印到文件中去

{

fprintf(fpw,"%c %d %d %d %d\n",str[i],ht1[i].weight,ht1[i].parent,ht1[i].lchild,ht1 [i].rchild);

}

fclose(fpw);

}

if(q=='E')

{

j=1;

i=1;

fpr=fopen("tobetran.txt","r");

fpr2=fopen("hfmtree.txt","r");

fpw2=fopen("codefile.txt","w");

while(fscanf(fpr2,"%c %d %d %d %d\n",&str[j],&ht1[j].weight,&ht1[j].parent,&ht1[j]. lchild,&ht1[j].rchild)!=EOF)

{

j++; //计数,哈夫曼树值大小

}

while(fscanf(fpr,"%c",&dst[i])!=EOF)

{

i++; //所输入文件字符大小

}

count=j; //count代表就是哈夫曼树大小,count1代表输入文件大小

count1=i;

crthuffmancode(ht1,hc1,count-1); //重新从文件里建立哈夫曼编码表

for(i=1;i<=count1-1;i++)

{

for(j=1;j<=count/2;j++) //count/2就是字符集大小了

{

if(dst[i]==str[j]) //比较

{

fprintf(fpw2,"%s",hc1[j]); //找到后写入对应的编码到文件中去,也就是codefile那个文件

}

}

}

fclose(fpr);

fclose(fpr2);

fclose(fpw2);

}

if(q=='D')

{

j=1;

i=1;

z=1;

fpr2=fopen("hfmtree.txt","r");

fpw3=fopen("textfile.txt","w");

while(fscanf(fpr3,"%c",&dst[i])!=EOF)

{

i++;

}

count3=i;

while(fscanf(fpr2,"%c %d %d %d %d\n",&str[j],&ht1[j].weight,&ht1[j].parent,&ht1[j].lchi ld,&ht1[j].rchild)!=EOF)

{

j++;

}

count2=j; //count2是哈夫曼树大小计数,count3是读入的哈夫曼编码计数

crthuffmancode(ht1,hc1,count2-1); //重新建立哈夫曼编码表

for(i=1;i

{

for(j=1;j<=count2/2;j++)

{

len=strlen(hc1[j]); //对每个字符哈夫曼编码长度统计

for(t=0;t

{

if(hc1[j][t]==dst[t+i]) //这里就相当字符匹配了

{

flag=1;

}

if(hc1[j][t]!=dst[t+i])

{

flag=0;

break;

}

}

if(flag==1&&t==len) //判断

{

win[z]=str[j]; //写入字符

z++;

i=i+len-1;

break;

}

}

}

count4=z;

for(z=1;z

{

fprintf(fpw3,"%c",win[z]);

}

fclose(fpr2);

fclose(fpr3);

fclose(fpw3);

}

if(q=='P') //打印codefile文件

{

j=1;

fpr2=fopen("codefile.txt","r");

fpw3=fopen("codeprin.txt","w");

while(fscanf(fpr2,"%c",&dst[j])!=EOF)

{

j++;

}

count=j;

j=0;

for(i=1;i

{

j++;

if(j==50)

{

printf("\n");

j=0;

}

printf("%c",dst[i]);

fprintf(fpw3,"%c",dst[i]);

}

fclose(fpr2);

fclose(fpw3);

}

if(q=='T') //打印哈夫曼树,完备的树结构不好打印,这里就是通过本身结构大致打印出来

{

fpw=fopen("treeprin.txt","w");

fpr=fopen("hfmtree.txt","r");

i=1;

m=0;

while(fscanf(fpr,"%c %d %d %d %d\n",&str[i],&ht1[i].weight,&ht1[i].parent,&ht1[ i].lchild,&ht1[i].rchild)!=EOF)

{

m++;

i++;

}

n=(m+1)/2; //字符集大小

crthuffmancode(ht1,hc1,n); //重新建立哈夫曼编码表

for(i=1;i<=n;i++)

{

len=strlen(hc1[i]);

if(maxlen

maxlen=len;

}

count=maxlen; //求得最大字符编码长度,用来控制行数的

for(i=1;i<=m;i++)

{

t=0;

if(ht1[i].parent==0) //先寻找根节点,打印出来

{

for(c=0;c<2*count;c++) //打印空格

{

printf(" ");

fprintf(fpw," ");

}

printf("%d\n",ht1[i].weight);

fprintf(fpw,"%d\n",ht1[i].weight);

count=count-1; //跳入下一行

j=ht1[i].lchild;

low[t]=j; /记录根节点右子树,用数组low[]

t++;

k=ht1[i].rchild; //记录根节点左子树

low[t]=k;

t++;

for(c=0;c<2*count;c++) //打空格

{

printf(" ");

fprintf(fpw," ");

}

printf("%d ",ht1[j].weight);

//打印根节点的右子树和左子树

fprintf(fpw,"%d ",ht1[j].weight);

printf(" ");

fprintf(fpw," ");

printf("%d\n",ht1[k].weight);

fprintf(fpw,"%d\n",ht1[k].weight);

count=count-1;

}

}

p=0;

while(p

{

for(j=0;j<2*count;j++)

{

printf(" ");

}

y=t; //y作为每一行节点数的记录用

t=0;

for(i=0;i

{

if(ht1[low[i]].lchild!=0)

{

printf("%d ",ht1[ht1[low[i]].lchild].weight);

fprintf(fpw,"%d ",ht1[ht1[low[i]].lchild].weight);

}

else

{

printf("0 ");

fprintf(fpw," ");

}

if(ht1[low[i]].rchild!=0)

{

printf("%d ",ht1[ht1[low[i]].rchild].weight);

fprintf(fpw,"%d ",ht1[ht1[low[i]].rchild].weight);

}

else

{

printf("0 ");

fprintf(fpw," ");

}

if(ht1[low[i]].lchild!=0) //记录本层的孩子数量和位置,用数组d[] {

d[t]=ht1[low[i]].lchild;

t++;

}

if(ht1[low[i]].rchild!=0)

{

d[t]=ht1[low[i]].rchild;

t++;

}

}

for(i=0;i

{

low[i]=d[i];

}

printf("\n");

p++;

count=count-1;

fclose(fpw); //记住关文件

fclose(fpr);

}

}

return 0;

}

函数的调用关系

Mian

Crthuffmancode crthuffmantree select

设计和调试分析

1、打印树本来是考虑用严格格式输出,但是需要空间太大,就用类似树的形式输出

2、文件操作最后必须要关闭文件,否则会一直在缓冲区中

3、注意关闭指针

用户手册

用户界面如下

用户需要预先准备好totran文件,然后根据提示输入字符集大小和每个字母和对应的权值,然后按

E编译代码,D印刷代码,P打印哈夫曼树到文件和终端上。

测试结果

测试数据为

A B C D E F G H I J K L M N O 符

64 13 22 32 103 21 15 47 57 1 5 32 20 57 63 权

P Q R S T U V W X Y Z

15 1 48 51 80 23 8 18 1 16 1

测试语句为:

THIS PROGRAME IS MY FAVORITE

输出hfmcode文件110100010110001111110001000101001100001001010101100100101110110001111111001010001111111 0011101011000001001001001101101010111

打印哈夫曼树

814

347 467

156 191 217 250

76 80 92 99 103 114 122 128

35 41 45 47 48 51 57 57 59 63 64 64

17 18 20 21 22 23 28 31 32 32

8 9 13 15 15 16

4 5

2 2

附录

程序源文件

(

#include

#include

#include

#include

#define N 100

#define M 2*N+1

#define maxint 32767

typedef struct //定义哈夫曼树的结构

{

int weight;

int parent;

int lchild;

int rchild;

}htnode,huffmantree[M+1];

int j,m1,m2;

m1=m2=maxint;

for(j=1;j<=pos;j++)

{

if(ht[j].weight

{

m2=m1;

*s2=*s1;

*s1=j;

m1=ht[j].weight;

}

else if(ht[j].weight

{

m2=ht[j].weight;

*s2=j;

}

}

}

void crthuffmantree(huffmantree ht,int w[],int n) //初始化哈夫曼树

{

int i,s1,s2,m;

for(i=1;i<=n;i++) //对字母建立哈夫曼树的结构

{

ht[i].weight=w[i];

ht[i].parent=0;

ht[i].lchild=0;

ht[i].rchild=0;

}

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;

typedef char *huffmancode[N+1]; //建立哈夫曼树编码表,这里采用的是指针的形式

void crthuffmancode(huffmantree ht,huffmancode hc,int n)

{ //变量说明一下,start用于从根部开始逆向求哈夫曼编码的一个参数,每当录入一个值其结果减1,类似短除法求二进制转换

//参数c表示某个节点自身的位置,而p是其双亲的位置

char *cd; //新建立一个指针

int start,i,c,p;

cd=(char*)malloc(n*sizeof(char)); //分配求一个字符的哈夫曼编码的空间

cd[n-1]='\0'; //编码结束符

for(i=1;i<=n;i++)

{

start=n-1;

c=i;

p=ht[i].parent;

while(p!=0) //因为只有根的双亲为0,所以相当于逆向遍历到根

{

--start;

if(ht[p].lchild==c) //如果双亲的左孩子等于该值在则该值就是左孩子,否则为右孩子,分别对应0,1

cd[start]='0';

else

cd[start]='1';

c=p; //向上走

p=ht[p].parent;

}

hc[i]=(char *)malloc((n-start)*sizeof(char)); //这是我们实质储存的空间,应该该叫数组指针

strcpy(hc[i],&cd[start]); //字符串复制

}

free(cd);

}

int main()

{

FILE *fpw,*fpr,*fpw2,*fpr2,*fpr3,*fpw3,*ftest;

int

n=0,d[1000],m,low[1000],weight[10000]={0},i,j=0,count=0,count1=0,count3=0,z=1,count4=0, count2=0,len,t,flag=0,c,maxlen,k,p,y;

char str[10000]={0},q,dst[10000]={0},com[10000]={0},win[10000]={0},a;

huffmantree ht1;

huffmancode hc1;

printf("请输入:初始化 I;编码 E;译码 D;印代码文件 P;印哈弗曼树 T\n");

printf("结束请输入Q\n");

while(1)

{ //这就是用户输入

if(q=='Q')

{

break;

}

if(q=='I')

{

fpw=fopen("hfmtree.txt","w");

ftest=fopen("date.txt","r");

printf("请输入密码表,第一位表示密码表大小,之后按空格键开始以紧凑的格式输入编码字母和权值。\n");

scanf("%d",&n); //字符集大小输入

getchar(); //吃空格用的

for(i=1;i<=n;i++) //这里本来是要在终端输入的,我为了图个测试方便就写文件里,可以自己改回来

{

fscanf(ftest,"%c",&a);

if(a!='\n')

{

str[i]=a;

fscanf(ftest,"%d",&weight[i]);

}

else i--; //减去回车键的计数,应该是用于输入量过多情况下需要隔行输入的设定

}

for(i=n+1;i<=2*n-1;i++) //补全剩余的

{

str[i]='0';

}

crthuffmantree(ht1,weight,n); //建立哈夫曼树

crthuffmancode(ht1,hc1,n); //建立哈夫曼编码表

for(i=1;i<=2*n-1;i++) //打印到文件中去

{

fprintf(fpw,"%c %d %d %d %d\n",str[i],ht1[i].weight,ht1[i].parent,ht1[i].lchild,ht1 [i].rchild);

}

fclose(ftest); //关闭文件,这点很重要,否则文件不会写入

fclose(fpw);

}

if(q=='E')

{

j=1;

i=1;

fpr=fopen("tobetran.txt","r");

fpr2=fopen("hfmtree.txt","r");

fpw2=fopen("codefile.txt","w");

while(fscanf(fpr2,"%c %d %d %d %d\n",&str[j],&ht1[j].weight,&ht1[j].parent,&ht1[j].

{

j++; //计数,哈夫曼树值大小

}

while(fscanf(fpr,"%c",&dst[i])!=EOF)

{

i++; //所输入文件字符大小

}

count=j; //count代表就是哈夫曼树大小,count1代表输入文件大小

count1=i;

crthuffmancode(ht1,hc1,count-1); //重新从文件里建立哈夫曼编码表

for(i=1;i<=count1-1;i++)

{

for(j=1;j<=count/2;j++) //count/2就是字符集大小了

{

if(dst[i]==str[j]) //比较

{

fprintf(fpw2,"%s",hc1[j]); //找到后写入对应的编码到文件中去,也就是codefile那个文件

}

}

}

fclose(fpr);

fclose(fpr2);

fclose(fpw2);

}

if(q=='D')

{

j=1;

i=1;

z=1;

fpr2=fopen("hfmtree.txt","r");

fpr3=fopen("codefile.txt","r");

fpw3=fopen("textfile.txt","w");

while(fscanf(fpr3,"%c",&dst[i])!=EOF)

{

i++;

}

count3=i;

while(fscanf(fpr2,"%c %d %d %d %d\n",&str[j],&ht1[j].weight,&ht1[j].parent,&ht1[j].lchi ld,&ht1[j].rchild)!=EOF)

{

j++;

count2=j; //count2是哈夫曼树大小计数,count3是读入的哈夫曼编码计数

crthuffmancode(ht1,hc1,count2-1); //重新建立哈夫曼编码表

for(i=1;i

{

for(j=1;j<=count2/2;j++)

{

len=strlen(hc1[j]); //对每个字符哈夫曼编码长度统计

for(t=0;t

{

if(hc1[j][t]==dst[t+i]) //这里就相当字符匹配了

{

flag=1;

}

if(hc1[j][t]!=dst[t+i])

{

flag=0;

break;

}

}

if(flag==1&&t==len) //判断

{

win[z]=str[j]; //写入字符

z++;

i=i+len-1;

break;

}

}

}

count4=z;

for(z=1;z

{

fprintf(fpw3,"%c",win[z]);

}

fclose(fpr2);

fclose(fpr3);

fclose(fpw3);

}

if(q=='P') //打印codefile文件

{

j=1;

fpw3=fopen("codeprin.txt","w");

while(fscanf(fpr2,"%c",&dst[j])!=EOF)

{

j++;

}

count=j;

j=0;

for(i=1;i

{

j++;

if(j==50)

{

printf("\n");

j=0;

}

printf("%c",dst[i]);

fprintf(fpw3,"%c",dst[i]);

}

fclose(fpr2);

fclose(fpw3);

}

if(q=='T') //打印哈夫曼树,完备的树结构不好打印,这里就是通过本身结构大致打印出来

{

fpw=fopen("treeprin.txt","w");

fpr=fopen("hfmtree.txt","r");

i=1;

m=0;

while(fscanf(fpr,"%c %d %d %d %d\n",&str[i],&ht1[i].weight,&ht1[i].parent,&ht1[ i].lchild,&ht1[i].rchild)!=EOF)

{

m++;

i++;

}

n=(m+1)/2; //字符集大小

maxlen=0; //最大子符编码长度

crthuffmancode(ht1,hc1,n); //重新建立哈夫曼编码表

for(i=1;i<=n;i++)

{

len=strlen(hc1[i]);

if(maxlen

maxlen=len;

}

count=maxlen; //求得最大字符编码长度,用来控制行数的

for(i=1;i<=m;i++)

{

if(ht1[i].parent==0) //先寻找根节点,打印出来

{

for(c=0;c<2*count;c++) //打印空格

{

printf(" ");

fprintf(fpw," ");

}

printf("%d\n",ht1[i].weight);

fprintf(fpw,"%d\n",ht1[i].weight);

count=count-1; //跳入下一行

j=ht1[i].lchild;

low[t]=j; //记录根节点右子树,用数组low[]

t++;

k=ht1[i].rchild; //记录根节点左子树

low[t]=k;

t++;

for(c=0;c<2*count;c++) //打空格

{

printf(" ");

fprintf(fpw," ");

}

printf("%d ",ht1[j].weight); //打印根节点的右子树和左子树

fprintf(fpw,"%d ",ht1[j].weight);

printf(" ");

fprintf(fpw," ");

printf("%d\n",ht1[k].weight);

fprintf(fpw,"%d\n",ht1[k].weight);

count=count-1;

}

}

p=0;

while(p

{

for(j=0;j<2*count;j++)

{

printf(" ");

fprintf(fpw," ");

}

y=t; //y作为每一行节点数的记录用

t=0;

for(i=0;i

{

if(ht1[low[i]].lchild!=0)

{

printf("%d ",ht1[ht1[low[i]].lchild].weight);

fprintf(fpw,"%d ",ht1[ht1[low[i]].lchild].weight);

else

{

printf("0 ");

fprintf(fpw," ");

}

if(ht1[low[i]].rchild!=0)

{

printf("%d ",ht1[ht1[low[i]].rchild].weight);

fprintf(fpw,"%d ",ht1[ht1[low[i]].rchild].weight);

}

else

{

printf("0 ");

fprintf(fpw," ");

}

if(ht1[low[i]].lchild!=0) //记录本层的孩子数量和位置,用数组d[]

{

d[t]=ht1[low[i]].lchild;

t++;

}

if(ht1[low[i]].rchild!=0)

{

d[t]=ht1[low[i]].rchild;

t++;

}

}

for(i=0;i

{

low[i]=d[i];

}

printf("\n");

fprintf(fpw,"\n");

p++;

count=count-1;

}

fclose(fpw); //记住关文件

fclose(fpr);

}

}

return 0;

}

)

THIS PROGRAME IS MY FAVORITE

Date.txt

A64B13C22D32E103F21G15H47I57J1K5L32M20N57O63P15Q1R48S51T80U23V8W18X1Y16Z1 Codefile.txt

Codeprint.txt

Hfmtree.txt

Textfile.txt

哈夫曼树编码译码实验报告(DOC)

数据结构课程设计设计题目:哈夫曼树编码译码

目录 第一章需求分析 (1) 第二章设计要求 (1) 第三章概要设计 (2) (1)其主要流程图如图1-1所示。 (3) (2)设计包含的几个方面 (4) 第四章详细设计 (4) (1)①哈夫曼树的存储结构描述为: (4) (2)哈弗曼编码 (5) (3)哈弗曼译码 (7) (4)主函数 (8) (5)显示部分源程序: (8) 第五章调试结果 (10) 第六章心得体会 (12) 第七章参考文献 (12) 附录: (12)

在当今信息爆炸时代,如何采用有效的数据压缩技术节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视,哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。哈夫曼编码是一种编码方式,以哈夫曼树—即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。哈弗曼编码使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。哈夫曼编码的应用很广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个叶子对应的字符的编码,这就是哈夫曼编码。哈弗曼译码输入字符串可以把它编译成二进制代码,输入二进制代码时可以编译成字符串。 第二章设计要求 对输入的一串电文字符实现哈夫曼编码,再对哈夫曼编码生成的代码串进行译码,输出电文字符串。通常我们把数据压缩的过程称为编码,解压缩的过程称为解码。电报通信是传递文字的二进制码形式的字符串。但在信息传递时,总希望总长度能尽可能短,即采用最短码。假设每种字符在电文中出现的次数为Wi,编码长度为Li,电文中有n种字符,则电文编码总长度为∑WiLi。若将此对应到二叉树上,Wi为叶结点的权,Li为根结点到叶结点的路径长度。那么,∑WiLi 恰好为二叉树上带权路径长度。因此,设计电文总长最短的二进制前缀编码,就是以n种字符出现的频率作权,构造一棵哈夫曼树,此构造过程称为哈夫曼编码。设计实现的功能: (1) 哈夫曼树的建立; (2) 哈夫曼编码的生成; (3) 编码文件的译码。

哈夫曼编码实验报告

中南大学数据结构课程 姓名:刘阳 班级:信息0703 学号:0903070312 实验时间: 08.11.14 指导老师:赵颖

一、实验内容 根据输入的n 个带权结点,构造出哈夫曼树,并且把构造结果输出到屏幕。 二、实验说明 哈夫曼数,也称最优二叉树,是指对于一组带有确定权值的叶结点,构造的具有最小带权路径长度的二叉树。 设二叉树具有n 个带权值的叶结点,那么从根结点到各个叶结点的路径长度与相应结点权值的乘积之和叫做二叉树的带权路径长度WPL ,记作: WPL=k n k k L W *∑=1。在给定一组具有确定权值的叶结点,可以构造出不同的带权二 叉树。根据哈夫曼树的定义,一棵二叉树要使其WPL 值最小,必须使权值越大的叶结点越靠近根结点,而权值越小的叶结点越远离根结点。 在数据通讯中,经常需要将传送的文字转换成由二进制字符0,1组成的二进制串,我们称之为编码。例如,假设要传送的电文为ABACCDA ,电文中只含有A ,B ,C ,D 四种字符,若这四种字符采用下表所示的编码,则电文的代码为000010000100100111 000,长度为21。 在传送电文时,我们总是希望传送时间尽可能短,这就要求电文代码尽可能短。如果在编码时考虑字符出现的频率,让出现频率高的字符采用尽可能短的编码,出现频率低的字符采用稍长的编码,构造一种不等长编码,则电文的代码就可能更短。并且在建立不等长编码时,必须使任何一个字符的编码都不是另一个字符编码的前缀,以避免反译成原文时,编码出现多义性。 在哈夫曼编码树中,树的带权路径长度的含义是各个字符的码长与其出现次数的乘积之和,也就是电文的代码总长,所以采用哈夫曼树构造的编码是一种能使电文代码总长最短的不等长编码。 采用哈夫曼树进行编码,也不会产生上述二义性问题。因为,在哈夫曼树中,每个字符结点都是叶结点,它们不可能在根结点到其它字符结点的路径上,所以一个字符的哈夫曼编码不可能是另一个字符的哈夫曼编码的前缀,从而保证了译码的非二义性。

数据结构实验报告哈夫曼树

数据结构实验报告实验题目: Huffman编码与解码 姓名: 学号: 院系:

实验名称: Huffman编码与解码实验 问题描述: 本实验需要以菜单形式完成以下功能: 1、输入电文串 2、统计电文串中各个字符及其出现的次数 3、构造哈弗曼树 4、进行哈弗曼编码 5、将电文翻译成比特流并打印出来 6、将比特流还原成电文 数据结构的描述: 逻辑结构: 本实验可用二叉树实现,其逻辑结构为一对二的形式,即一个结点对应两个结点。在实验过程中我们也应用到了栈的概念。 存储结构: 使用结构体来对数据进行存储: typedef struct { int weight; int parent,lc,rc; }HTNode,*HuffmanTree; typedef struct LNode { char *elem; int stacksize; int top; }SqStack; 在main函数里面定义一个哈弗曼树并实现上述各种功能。 程序结构的描述: 本次实验一共构造了10个函数: 1.void HuffTree(HuffmanTree &HT,int n[],int mun); 此函数根据给定的mun个权值构建哈弗曼树,n[]用于存放num个权值。 2、void Select(HuffmanTree &HT,int n,int i,int &s1,int &s2);

此函数用于在HT[1,i-1]中选择parent为0且weight为最小的两个结点,其下标分别为s1,s2、 3.void HuffmanCoding(HuffmanTree HT,char **&HC,int n); 此函数从哈弗曼树HT上求得n 个叶子结点的哈弗曼编码并存入数组HC中。 4.void Coding(HuffmanTree HT,char **HC,int root,SqStack &S); 此函数用于哈弗曼编码,先序遍历哈弗曼树HT,求得每个叶子结点的编码字符串,存入数组HC,S为一个顺序栈,用来记录遍历路径,root就是哈弗曼数组HT中根结点的位置下标。 5.void InitStack(SqStack &S); 此函数用于初始化一个栈。 6.void Pop(SqStack &S,char e); 此函数为出栈操作。 7.void Push(SqStack &S,char e); 此函数为进栈操作。 8.int StackLength(SqStack S); 此函数用于求栈长,返回一个int型的值。 9.int Find(char a,char s[],int num); 此函数用于查找字符a在电文串中的位置。 10.int Recover(HuffmanTree HT,char **HC,char string[],char a[],char b[],int n); 此函数用于将比特流还原成电文。 调试分析: 输入任意一个字符串,如输入welcometoustc:运行结果如下:

霍夫曼树实验报告

实验二二叉树的遍历及霍夫曼编码 班级:计科1101班 学号:0909101605 姓名:杜茂鹏 2013年5月22日

一、实验目的 掌握二叉树的建立及遍历操作,霍夫曼编码基本操作及存储结构表示 二、实验内容 1. 系统要求包含以下功能 1)初始化:从终端读入字符集大小n,以及n个字符和n个权值(或者读入字符集和频度数据文件),建立哈夫曼树,并将哈夫曼树存入到文件HfmTree 中。 2)编码:利用已建好的哈夫曼树(如果不在内存中,则从文件中读入),从文件ToBeTran中读入原文,对原文进行编码,将编码后的结果存入文件CodeFile 中。 3)译码:利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。 4)打印:打印输出哈夫曼树,显示ToBeTran, TextFile和CodeFile文件的内容。 三、实验要求 1.在上机前写出全部源程序; 2.能在机器上正确运行程序; 3.用户界面友好。 四、概要设计 1)首先动态分配数组存储霍夫曼树及存储霍夫曼编码表,然后从终端或文件读入霍夫曼树的字符变量及其频度,初始化建立霍夫曼树并将其写入文件HfmTree.txt中。 2)从指定的文件succe.txt中读入原文,利用已经编好的霍夫曼树对其编码,将编码结果写入文件Coding.txt保存。 3)利用已建好的哈夫曼树将文件Coding.txt中的代码进行译码,结果存入文件decoding.txt中。

五、测试数据: 2.原文内容“THIS IS MY PROGRAM” 六、详细设计 实验内容(原理、操作步骤、程序代码) //建立霍夫曼树,对原文进行编码、译码 #include #include #include #include typedef struct tree { char ch; int weight;//权值 int parent,lchild,rchild; }HTNode,*HuffmanTree;//动态分配数组存储霍夫曼树typedef char **HuffmanCode;//动态分配数组存储霍夫曼编码表void Select(HuffmanTree &HT,int* s1,int* s2,int n) { int j; int min1=10000; for(j=1;j<=n;j++) { if(HT[j].parent==0&&min1>HT[j].weight)

哈夫曼树实验报告

哈夫曼树实验报告 Company number:【0089WT-8898YT-W8CCB-BUUT-202108】

计算机科学与技术学院数据结构实验报告 班级 2014级计算机1班学号姓名张建华成绩 实验项目简单哈夫曼编/译码的设计与实现实验日期一、实验目的 本实验的目的是进一步理解哈夫曼树的逻辑结构和存储结构,进一步提高使用理论知识指导解决实际问题的能力。 二、实验问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码,此实验即设计这样的一个简单编/码系统。系统应该具有如下的几个功能: 1、接收原始数据。 从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件中。 2、编码。 利用已建好的哈夫曼树(如不在内存,则从文件中读入),对文件中的正文进行编码,然后将结果存入文件中。 3、译码。 利用已建好的哈夫曼树将文件中的代码进行译码,结果存入文件中。 4、打印编码规则。 即字符与编码的一一对应关系。 5、打印哈夫曼树, 将已在内存中的哈夫曼树以直观的方式显示在终端上。 三、实验步骤 1、实验问题分析 1、构造哈夫曼树时使用静态链表作为哈夫曼树的存储。 在构造哈夫曼树时,设计一个结构体数组HuffNode保存哈夫曼树中各结点的信息,根据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有2n-1个结点,所以数组HuffNode的大小设置为2n-1,描述结点的数据类型为: Typedef strcut { Int weight;/*结点权值*/ Int parent; Int lchild; Int rchild; }HNodeType; 2、求哈夫曼编码时使用一维结构数组HuffCode作为哈夫曼编码信息的存储。 求哈夫曼编码,实质上就是在已建立的哈夫曼树中,从叶子结点开始,沿结点的双亲链域回退到根结点,没回退一步,就走过了哈夫曼树的一个分支,从而得到一位哈夫曼码值,由于一个字符的哈夫曼编码是从根结点到相应叶子结点所经过的路

哈弗曼数据结构专题实验报告

数据结构与程序设计专题 实验报告 :学号:班级:信息45班 :学号:班级:信息45班 :学号:班级:信息45班 实验指导老师:峰 实验地点:西一楼一层计算机中心机房 实验结束日期:12月5日 联系:

一.实验任务: 对于给定的源文档 SourceDoc.txt, 1) 统计其中所有字符的频度(某字符的频度等于其出现的总次数除以总字符数),字符包括字母(区分大小写)、标点符号及格式控制符(空格、回车等)。 2) 按频度统计结果构建哈夫曼编码表。 3) 基于哈夫曼编码表进行编码,生成对应的二进制码流,并输出到文件 Encode.dat,完成信源的编码过程。 4) 根据生成的哈夫曼编码表,对二进制码流文件 Encode.dat 进行解码,把结果输出到文件 TargetDoc.txt,完成信源的解码过程。 5) 判断 TargetDoc.txt 与 SourceDoc.txt 容是否一致,以验证编解码系统的正确性。 二.实验容: 1) 线性链表的构建以及排序; 2) 哈夫曼树的构建; 3) 基于哈夫曼码进行编码; 4) 对二进制码进行解码; 5)对生成文件与原文件进行比较; 三.程序的算法描述

四.程序运行结果:

五.源程序代码: #include #include #include #include typedef struct aa {char data; double rate; int count; struct aa *next; struct aa *pre; char haffmancode[120]; }NODE; NODE *creat(char b[])

哈夫曼树 实验报告

计算机科学与技术学院数据结构实验报告 班级2014级计算机1班学号20144138021 姓名张建华成绩 实验项目简单哈夫曼编/译码的设计与实现实验日期2016.1.5 一、实验目的 本实验的目的是进一步理解哈夫曼树的逻辑结构和存储结构,进一步提高使用理论知识指导解决实际问题的能力。 二、实验问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码,此实验即设计这样的一个简单编/码系统。系统应该具有如下的几个功能: 1、接收原始数据。 从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmtree.dat中。 2、编码。 利用已建好的哈夫曼树(如不在内存,则从文件hfmtree.dat中读入),对文件中的正文进行编码,然后将结果存入文件codefile.dat中。 3、译码。 利用已建好的哈夫曼树将文件codefile.dat中的代码进行译码,结果存入文件textfile.dat中。 4、打印编码规则。 即字符与编码的一一对应关系。 5、打印哈夫曼树, 将已在内存中的哈夫曼树以直观的方式显示在终端上。 三、实验步骤 1、实验问题分析 1、构造哈夫曼树时使用静态链表作为哈夫曼树的存储。 在构造哈夫曼树时,设计一个结构体数组HuffNode保存哈夫曼树中各结点的信息,根据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有2n-1个结点,所以数组HuffNode的大小设置为2n-1,描述结点的数据类型为: Typedef strcut { Int weight;/*结点权值*/ Int parent; Int lchild; Int rchild; }HNodeType; 2、求哈夫曼编码时使用一维结构数组HuffCode作为哈夫曼编码信息的存储。 求哈夫曼编码,实质上就是在已建立的哈夫曼树中,从叶子结点开始,沿结点的双亲链域回退到根结点,没回退一步,就走过了哈夫曼树的一个分支,从而得到一位哈夫曼码值,由于一个字符的哈夫曼编码是从根结点到相应叶子结点所经过的路径上各分支所组成的0、1序列,因此先得到的分支代码为所求编码的低位码,后得到的分支代码位所求编码的高位码,所以设计如下数据类型:

哈夫曼树的实验报告1

一、需求分析 1、本演示程序实现Haffman编/译码器的作用,目的是为信息收发站提供一个编/译系统, 从而使信息收发站利用Haffman编码进行通讯,力求达到提高信道利用率,缩短时间,降低成本等目标。系统要实现的两个基本功能就是:①对需要传送的数据预先编码; ②对从接收端接收的数据进行译码; 2、本演示程序需要在终端上读入n个字符(字符型)及其权值(整形),用于建立Huffman 树,存储在文件hfmanTree.txt中;如果用户觉得不够清晰还可以打印以凹入表形式显示的Huffman树; 3、本演示程序根据建好的Huffman树,对文件的文本进行编码,结果存入文件CodeFile 中;然后利用建好的Huffman树将文件CodeFile中的代码进行译码,结果存入文件TextFile中;最后在屏幕上显示代码(每行50个),同时显示对CodeFile中代码翻译后的结果; 4、本演示程序将综合使用C++和C语言; 5、测试数据: (1)教材例6-2中数据:8个字符,概率分别是0.05,0.29,0.07,0.08,0.14,0.23,0.03, 0.11,可将其的权值看为5,29,7,8,14,23,3,11 (2)用下表给出的字符集和频度的实际统计数据建立Haffman树,并实现以下报文的编码和 一、概要设计 1、设定哈夫曼树的抽象数据类型定义 ADT Huffmantree{ 数据对象:D={a i| a i∈Charset,i=1,2,3,……n,n≥0} 数据关系:R1={< a i-1, a i >| a i-1, a i∈D, i=2,3,……n} 基本操作: Initialization(&HT,&HC,w,n,ch) 操作结果:根据n个字符及其它们的权值w[i],建立Huffman树HT,用字符数组ch[i]作为中间存储变量,最后字符编码存到HC中; Encodeing(n) 操作结果:根据建好的Huffman树,对文件进行编码,编码结果存入到文件CodeFile 中 Decodeing(HT,n) 操作结果:根据已经编译好的包含n个字符的Huffman树HT,将文件的代码进行翻译,结果存入文件TextFile中 } ADT Huffmantree

哈夫曼编码解码实验报告

哈夫曼编码解码实验 1.实验要求 掌握二叉树的相关概念 掌握构造哈夫曼树,进行哈夫曼编码。 对编码内容通过哈夫曼树进行解码。 2.实验内容 通过二叉树构造哈夫曼树,并用哈夫曼树对读取的txt文件进行哈夫曼编码。编码完成后通过哈夫曼树进行解码。 #include #include #define MAX 100 //定义哈夫曼树的存储结构 typedef struct { char data; int weight; int parent; int lch; int rch; }HuffNode; //定义哈夫曼编码的存储结构 typedef struct { char bit[MAX]; int start; }HuffCode; HuffNode ht[2*MAX]; HuffCode hcd[MAX]; int Coun[127]={0}; int n; char s1[200000]; char text[5000]; //构造哈夫曼树 void HuffmanTree() {

int i,j,k,left,right,min1,min2; //printf("输入叶子的节点数:"); //scanf("%d",&n); printf("字符数量=%d\n",n); for(i=1;i<=2*n-1;i++) { ht[i].parent=ht[i].lch=ht[i].rch=0; } j=0; for(i=1;i<=n;i++) { /*getchar(); printf("输入第%d个叶子节点的值:",i); scanf("%c",&ht[i].data); printf("输入该节点的权值:"); scanf("%d",&ht[i].weight); */ for(;j<127;j++) { if(Coun[j]!=0) { ht[i].data=j; //printf("%c",ht[i].data); ht[i].weight=Coun[j]; //printf("%d",ht[i].weight); break; } } j++; } printf("\n"); for(i=1;i<=n;i++) { printf("%c",ht[i].data); } printf("\n"); for(i=n+1;i<=2*n-1;i++) {//在前n个结点中选取权值最小的两个结点构成一颗二叉树 min1=min2=10000;//为min1和min2设置一个比所有权值都大的值 left=right=0; for(k=1;k<=i-1;k++) { if(ht[k].parent==0)//若是根结点 //令min1和min2为最小的两个权值,left和right

哈夫曼树实验报告

数据结构实验报告 实验名称:实验三哈夫曼树 学生姓名: 班级: 班内序号: 学号: 日期: 程序分析: 存储结构:二叉树 程序流程: template class BiTree { public: ) 1.初始化链表的头结点

2.获得输入字符串的第一个字符,并将其插入到链表尾部,n=1(n记录的是链 表中字符的个数) 3.从字符串第2个字符开始,逐个取出字符串中的字符 将当前取出的字符与链表中已经存在的字符逐个比较,如果当前取出的 字符与链表中已经存在的某个字符相同,则链表中该字符的权值加1。 如果当前取出的字符与链表中已经存在的字符都不相同,则将其加入到 链表尾部,同时n++ =n(tSize记录链表中字符总数,即哈夫曼树中叶子节点总数) 5.创建哈夫曼树 6.销毁链表 源代码: void HuffmanTree::Init(string Input) { Node *front=new Node; 建哈夫曼树(void HuffmanTree::CreateCodeTable(Node *p)) 算法伪代码: 1.创建一个长度为2*tSize-1的三叉链表 2.将存储字符及其权值的链表中的字符逐个写入三叉链表的前tSize个结点 的data域,并将对应结点的孩子域和双亲域赋为空 3.从三叉链表的第tSize个结点开始,i=tSize 3.1从存储字符及其权值的链表中取出两个权值最小的结点x,y,记录其 下标x,y。 3.2将下标为x和y的哈夫曼树的结点的双亲设置为第i个结点 3.3将下标为x的结点设置为i结点的左孩子,将下标为y的结点设置为 i结点的右孩子,i结点的权值为x结点的权值加上y结点的权值,i 结点的双亲设置为空 4. 根据哈夫曼树创建编码表

哈夫曼编码译码系统课程设计实验报告(含源代码C++_C语言)

目录 摘要………………………………………………………………………..………………II Abstract …………………………………………………………………………..………... II 第一章课题描述 (1) 1.1 问题描述 (1) 1.2 需求分析…………………………………………………..…………………………… 1 1.3 程序设计目标…………………………………………………………………………… 第二章设计简介及设计方案论述 (2) 2.1 设计简介 (2) 2.2 设计方案论述 (2) 2.3 概要设计 (2) 第三章详细设计 (4) 3.1 哈夫曼树 (4) 3.2哈夫曼算 法 (4) 3.2.1基本思 想 (4) 3.2.2存储结 构 (4)

3.3 哈夫曼编码 (5) 3.4 文件I/O 流 (6) 3.4.1 文件流 (6) 3.4.2 文件的打开与关闭 (7) 3.4.3 文件的读写 (7) 3..5 C语言文件处理方式…………………………………………………………………… 第四章设计结果及分析 (8) 4.1 设计系统功能 (8) 4.2 进行系统测试 (8) 总结 (13) 致谢 (14) 参考文献 (15) 附录主要程序代码 (16) 摘要 在这个信息高速发展的时代,每时每刻都在进行着大量信息的传递,到处都离不开信息,它贯穿在人们日常的生活生产之中,对人们的影响日趋扩大,而利用哈夫曼编码

进行通信则可以大大提高信道利用率,缩短信息传输时间,降低传输成本。在生产中则可以更大可能的降低成本从而获得更大的利润,这也是信息时代发展的趋势所在。本课程设计的目的是使学生学会分析待加工处理数据的特性,以便选择适当的逻辑结构、存储结构以及进行相应的算法设计。学生在学习数据结构和算法设计的同时,培养学生的抽象思维能力、逻辑推理能力和创造性的思维方法,增强分析问题和解决问题的能力。此次设计的哈夫曼编码译码系统,实现对给定报文的编码和译码,并且任意输入报文可以实现频数的统计,建立哈夫曼树以及编码译码的功能。这是一个拥有完备功能的系统程序,对将所学到的知识运用到实践中,具有很好的学习和研究价值. 关键词:信息;通讯;编码;译码;程序 Abstract This is a date that information speeding highly development and transmit

哈夫曼树及其操作-数据结构实验报告(2)

电子科技大学 实验报告 课程名称:数据结构与算法 学生姓名:陈*浩 学号:************* 点名序号: *** 指导教师:钱** 实验地点:基础实验大楼 实验时间: 2014-2015-2学期 信息与软件工程学院

实验报告(二) 学生姓名:陈**浩学号:*************指导教师:钱** 实验地点:科研教学楼A508实验时间:一、实验室名称:软件实验室 二、实验项目名称:数据结构与算法—树 三、实验学时:4 四、实验原理: 霍夫曼编码(Huffman Coding)是一种编码方式,是一种用于无损数据压缩的熵编码(权编码)算法。1952年,David A. Huffman在麻省理工攻读博士时所发明的。 在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。 例如,在英文中,e的出现机率最高,而z的出现概率则最低。当利用霍夫曼编码对一篇英文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26)。用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个比特。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。 霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。 可以证明霍夫曼树的WPL是最小的。

数据结构实验三哈夫曼树实验报告

题目:哈夫曼编/译码器 一、题目要求: 写一个哈夫曼码的编/译码系统,要求能对要传输的报文进行编码和解码。构造哈夫曼树时,权值小的放左子树,权值大的放右子树,编码时右子树编码为1,左子树编码为0. 二、概要设计: 数据结构: typedef struct { int bit[MAXBIT]; int start; } HCodeType; /* 编码结构体 */ typedef struct { int weight; int parent; int lchild; int rchild; char value; } HNode; /* 结点结构体 */ 函数: void DEMONHuffmanTree (HNode HuffNode[MAXNODE], int n) 作用:构造一个哈夫曼树,并循环构建 int main () 作用:运用已经构建好的哈弗曼树,进行节点的处理,达到成功解码编译 三、详细设计: 哈夫曼树的建立: void DEMONHuffmanTree (HNode HuffNode[MAXNODE], int n) { int i = 0, j, m1, m2, x1, x2; char x; /* 初始化存放哈夫曼树数组 HuffNode[] 中的结点 */ while (i

HuffNode[i].rchild =-1; scanf("%c",&x); scanf("%c",&HuffNode[i].value); //实际值,可根据情况替换为字母 i++; } /* 输入 n 个叶子结点的权值 */ scanf("%c",&x); for(i=0;i

哈夫曼树及编码综合实验报告

《用哈夫曼编码实现文件压缩》 实验报告 课程名称数据结构B 实验学期 2017 至 2018 学年第一学期学生所在院部计算机学院 年级 2016 专业班级信管B162 学生姓名学号 成绩评定: 1、工作量: A(),B(),C(),D(),F( ) 2、难易度:A(),B(),C(),D(),F( ) 3、答辩情况: 基本操作:A(),B(),C(),D(),F( ) 代码理解:A(),B(),C(),D(),F( ) 4、报告规范度:A(),B(),C(),D(),F( ) 5、学习态度:A(),B(),C(),D(),F( )总评成绩:_________________________________ 指导教师: 兰芸

用哈夫曼编码实现文件压缩 1、了解文件的概念。 2、掌握线性链表的插入、删除等算法。 3、掌握Huffman树的概念及构造方法。 4、掌握二叉树的存储结构及遍历算法。 5、利用Huffman树及Huffman编码,掌握实现文件压缩的一般原理。 微型计算机、Windows 7操作系统、Visual C++6.0软件 输入的字符创建Huffman树,并输出各字符对应的哈夫曼编码。 五.系统设计 输入字符的个数和各个字符以及权值,将每个字符的出现频率作为叶子结点构建Huffman树,规定哈夫曼树的左分支为0,右分支为1,则从根结点到每个叶子结点所经过的分支对应的0和1组成的序列便为该结点对应字符的哈夫曼编码。 流程图如下 1.输入哈夫曼字数及相应权值

相应代码 int main() { HuffmanTree HTree; HuffmanCode HCode; int *w, i; int n,wei; //编码个数及权值 printf("请输入需要哈夫曼编码的字符个数:"); scanf("%d",&n); w=(int*)malloc((n+1)*sizeof(int)); for(i=1; i<=n;i++) { printf("请输入第%d字符的权值:",i); fflush(stdin); scanf("%d",&wei); w[i]=wei; } HuffmanCoding(&HTree,&HCode,w,n); return 1; } 2.输出HT初态(每个字符的权值)

哈夫曼树实验报告(付原C语言程序)

哈夫曼树实验报告 需求分析: 从终端读入一串字符,利用建立好的哈夫曼树对其进行编码,储存到文件当中去,然后从文件读入哈夫曼编码,针对每个字母对其进行译码,翻译为原来的信息。 二、概要设计 程序分为以下几个模块: 1、从终端读入字符集大小,n个字符和n个权值,建立哈夫曼树,写入文件hfmTree中去。 2、对hfmTree进行编码,建立hfm编码表。 3、从文件ToTran读入信息,根据hfm编码表对其进行hfm编码,将编码后的信息写入文件Codefile 中去 4、对Codefile文件反向译码,结果储存在Textfile中去。 5、将建立的hfmTree打印在终端上,并储存于相应的Treeprint文件中去。 抽象的数据定义如下: 哈夫曼树结构 typedef struct //定义哈夫曼树的结构 { int weight; //权值 int parent; //双亲 int lchild; //左孩子 int rchild; //右孩子 }htnode,huffmantree[M+1]; 建立哈夫曼树 void crthuffmantree(huffmantree ht,int w[],int n) //初始化哈夫曼树 { int i,s1,s2,m; for(i=1;i<=n;i++) { ht[i].weight=w[i]; ht[i].parent=0; ht[i].lchild=0; ht[i].rchild=0; } 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;

哈夫曼编码实验报告

哈夫曼编码: 哈夫曼编码,又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码。 发展历史: 1951年,哈夫曼和他在MIT信息论的同学需要选择是完成学期报告还是期末考试。导师Robert M. Fano给他们的学期报告的题目是,寻找最有效的二进制编码。由于无法证明哪个已有编码是最有效的,哈夫曼放弃对已有编码的研究,转向新的探索,最终发现了基于有序频率二叉树编码的想法,并很快证明了这个方法是最有效的。由于这个算法,学生终于青出于蓝,超过了他那曾经和信息论创立者香农共同研究过类似编码的导师。 1952年,David A. Huffman在麻省理工攻读博士时发表了《一种构建极小多余编码的方法》(A Method for the Construction of Minimum-Redundancy Codes)一文,它一般就叫做Huffman编码。 Huffman在1952年根据香农(Shannon)在1948年和范若(Fano)在1949年阐述的这种编码思想提出了一种不定长编码的方法,也称霍夫曼(Huffman)编码。霍夫曼编码的基本方法是先对图像数据扫描一遍,计算出各种像素出现的概率,按概率的大小指定不同长度的唯一码字,由此得到一张该图像的霍夫曼码表。编码后的

图像数据记录的是每个像素的码字,而码字与实际像素值的对应关系记录在码表中。 赫夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就称Huffman 编码。下面引证一个定理,该定理保证了按字符出现概率分配码长,可使平均码长最短。

树和哈夫曼树实验报告

树和哈夫曼树实验报告 一.实验目的 练习树和哈夫曼树的有关操作,和各个算法程序,理解哈夫曼树的编码和译码 二.实验环境 Microsoft visual c++ 三.实验问题描述 1. 问题描述:建立一棵用二叉链表方式存储的二叉树,并对其进行遍历(先序、中序和后序),打印输出遍历结果。 基本要求:从键盘接受输入先序序列,以二叉链表作为存储结构,建立二叉树(以先序来建立),并将此二叉树按照“树状形式”打印输出,然后对其进行遍历(先序、中序和后序),最后将遍历结果打印输出。在遍历算法中要求至少有一种遍历采用非递归方法。 测试数据: ABC??DE?G??F???(其中?表示空格字符) 输出结果为: 先序:ABCDEGF 先序:CBEGDFA 先序:CGEFDBA 2. 问题描述:利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接受端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站写一个哈夫曼码的编/译码系统。 基本要求:(至少完成功能1-2) 一个完整的系统应具有以下功能: I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。 基本要求: E:编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。 D:译码(Decoding )。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。 P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrint中。 T:印哈夫曼树(TreePrinting)。将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。 测试数据: 设权值w=(5,29,7,8,14,23,3,11),n=8。 按照字符‘0’或‘1’确定找左孩子或右孩子,则权值对应的编码为: 5:0001,29:11,7:1110,8:1111 14:110,23:01,3:0000,11:001 用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAM IS MY FAVORITE”。 四.实验主要程序流

数据结构实验三哈夫曼树实验报告

数据结构实验三哈夫曼树实验报告

题目:哈夫曼编/译码器 一、题目要求: 写一个哈夫曼码的编/译码系统,要求能对要传输的报文进行编码和解码。构造哈夫曼树时,权值小的放左子树,权值大的放右子树,编码时右子树编码为1,左子树编码为0. 二、概要设计: 数据结构: typedef struct { int bit[MAXBIT]; int start; } HCodeType; /* 编码结构体 */

typedef struct { int weight; int parent; int lchild; int rchild; char value; } HNode; /* 结点结构体 */ 函数: void DEMONHuffmanTree (HNode HuffNode[MAXNODE], int n) 作用:构造一个哈夫曼树,并循环构建 int main () 作用:运用已经构建好的哈弗曼树,进行节点的处理,达到成功解码编译 三、详细设计: 哈夫曼树的建立: void DEMONHuffmanTree (HNode HuffNode[MAXNODE], int n) { int i = 0, j, m1, m2, x1, x2; char x;

/* 初始化存放哈夫曼树数组HuffNode[] 中的结点*/ while (i

哈夫曼树及其操作-数据结构实验报告(2)

电子科技大学实验报告 课程名称:数据结构与算法学生姓名:陈*浩 学号:************* 点名序号:*** 指导教师:钱** 实验地点:基础实验大楼 实验时间:2015.5.7 2014-2015-2学期 信息与软件工程学院

实验报告(二) 学生姓名:陈**浩学号:*************指导教师:钱** 实验地点:科研教学楼A508实验时间:2015.5.7 一、实验室名称:软件实验室 二、实验项目名称:数据结构与算法—树 三、实验学时:4 四、实验原理: 霍夫曼编码(Huffman Coding)是一种编码方式,是一种用于无损数据压缩的熵编码(权编码)算法。1952年,David A. Huffman在麻省理工攻读博士时所发明的。 在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。 例如,在英文中,e的出现机率最高,而z的出现概率则最低。当利用霍夫曼编码对一篇英文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26)。用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个比特。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。 霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。 可以证明霍夫曼树的WPL是最小的。

相关文档
最新文档