赫夫曼树的应用.docx

上传人:b****7 文档编号:11270821 上传时间:2023-02-26 格式:DOCX 页数:18 大小:130.61KB
下载 相关 举报
赫夫曼树的应用.docx_第1页
第1页 / 共18页
赫夫曼树的应用.docx_第2页
第2页 / 共18页
赫夫曼树的应用.docx_第3页
第3页 / 共18页
赫夫曼树的应用.docx_第4页
第4页 / 共18页
赫夫曼树的应用.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

赫夫曼树的应用.docx

《赫夫曼树的应用.docx》由会员分享,可在线阅读,更多相关《赫夫曼树的应用.docx(18页珍藏版)》请在冰豆网上搜索。

赫夫曼树的应用.docx

赫夫曼树的应用

题目:

赫夫曼树的应用

课程名称:

《数据结构》课程设计

指导教师:

专业:

班级:

学号:

姓名:

学号:

姓名:

学号:

姓名:

学号:

姓名:

完成时间:

 

目录

一、前言2

二、程序设计目的3

三、需求分析3

四、概要设计3

1、主要需要用到的主要数据结构3

2、算法流程分析4

五、源程序和运行结果5

1.源程序如下5

2、运行结果11

六、调试分析14

1.测试的结果14

2.时间复杂度分析14

3.各模块在设计和调试时存在问题14

4.算法的改进设想14

七、设计心得和总结15

八、参考书籍15

一、前言

赫夫曼编码(HuffmanCoding)是一种编码方式,赫夫曼编码是可变字长编码(VLC)的一种。

赫夫曼压缩是个无损的压缩算法,一般用来压缩文本和程序文件。

赫夫曼压缩属于可变代码长度算法一族。

意思是个体符号(例如,文本文件中的字符)用一个特定长度的位序列替代。

因此,在文件中出现频率高的符号,使用短的位序列,而那些很少出现的符号,则用较长的位序列。

赫夫曼编码的应用很广泛,利用赫夫曼树求地的二进制编码称为赫夫曼编码。

赫夫曼树中从根到每个叶子都有一条路径,对路径上的各分支约定:

指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为对应的编码,这就是赫夫曼编码。

我们在对一些问题进行求解时,会发现有些问题很难找到规律,或者根本无规律可寻。

对于这样的问题,可以利用计算机运算速度快的特点,先搜索查找所有可能出现的情况,再根据题目条件从所有可能的情况中,删除那些不符合条件的解。

由赫夫曼算法的定义可知,初始森林中共有n棵只含有根结点的二叉树。

算法的的第二步是:

算法的的第二步是:

将当前森林中的两棵根结点权值最小的二叉树,合并成一棵新的二叉树,每合并一次,森林中就减少一棵树,产生一个新结点。

则要进行n-1次合并,所以共产生n-1个新结点。

由此可知,最终求得的赫夫曼树中一共有2n-1个结点。

其中,n个结点是初始森林中的n个孤立结点。

并且赫夫曼树中没有度数为1的分支的结点。

采用赫夫曼编码方案,即应用赫夫曼树构造使电文的编码总长最短的编码方案。

 

二、程序设计目的

1.熟悉掌握C语言的基础知识和技能;

2.学习利用计算机语言实现赫夫曼树构造的算法;

3.了解利用赫夫曼树对给定权值的字符的赫夫曼编码的算法思想。

三、需求分析

1、打开一个文本文件,用一个指针指向它,指针变量为*pf

2、对其进行字母频率统计,把字母和字母的频率放到结构体syrs1[]中

3、用Huffman算法建立Huffman树以及每个字母的Huffman码(Huffman数以及Huffman码两张表,均要求输出,最好能在文本中输出)

4、把该文本文件的英文文章利用Huffman树编码生成二进制文件(该文件要求输出)

5、打开该二进制文本文件,对其解码,仍然利用刚才的Huffman树进行解码

6、输入,输出要求都是读取文件。

四、概要设计

1、主要需要用到的主要数据结构

a、赫夫曼树的数据结构

typedefstruct

{

chardata;

intweight;

intparent;

intlchild;

intrchild;

}HuffmanTree[M];

b、赫夫曼编码的数据结构

typedefstruct

{

chardata;

charbits[N];

}HuffmanCode[N];

c、字符串存储单元的数据结构

typedefstructstr

{

chardata;

charnum;

//intnum;

}str;

2、算法流程分析

a、建立赫夫曼树的数据结构、赫夫曼编码的数据结构和字符串存储单元的数据结构,字符串存储单元的数据结构是用来存储字母和对应的权值。

b、调用intread(strs2[])函数,取读文本ywq1.txt并统计这里出现字符的个数(字母区分大小写、空格键和各种标点符号),再统计该字符在文本中出现的频率(也就是所谓的权值)存放在结构体strs2[]中,返回字母个数k,打印字母的和对应的权值。

c、调用CrtHuffmanTree(ht,s2,k)函数来创建赫夫曼数,首先初始化节点并给其赋值0,利用for的循环语句并调用SelectMin函数,查找哈夫曼链表中两个权值最小的来建立赫夫曼树,打印赫夫曼树各节点的权值和它的左右孩子。

d、调用CrtHuffmanCode(ht,hc,k)利用建立好的哈夫曼树对文本文本ywq1.txt进行编码,并把编译的赫夫曼编码储存在文本ywq2.txt中,并且打印出来文本的赫夫曼编码。

e、通过调用DecodHuffmanCode(ht,k)将文本ywq2.txt字符的赫夫曼码翻译为字符,这就是所谓的反译码,把翻译的英语文章存储在文本ywq3.txt并且存储,并且在对话执行框中打印出来。

五、源程序和运行结果

1.源程序如下

#include

#include

#include

#defineN100

#defineM2*N-1

typedefstruct//定义哈夫曼树存储节点结构体类型

{

chardata;

intweight;

intparent;

intlchild;

intrchild;

}HuffmanTree[M];

typedefstruct//定义哈夫曼编码结构体类型

{

chardata;

charbits[N];

}HuffmanCode[N];

typedefstructstr//定义字符串存储单元结构体类型

{

chardata;

charnum;

//intnum;

}str;

intread(strs2[])

{

FILE*fp;

charch;

inti,k;

strs1[128];

for(i=0;i<=128;i++)

{

s1[i].num=0;s1[i].data=0;

s2[i].num=0;s2[i].data=0;

}

if((fp=fopen("ywq1.txt","r"))==NULL)

{

printf("\n库文件不存在!

");

exit

(1);

}

printf("\n读取字符串为:

\n");

ch=fgetc(fp);

while(!

feof(fp))//统计字符频率

{

printf("%c",ch);

s1[ch].num++;

s1[ch].data=ch;

ch=fgetc(fp);

}

fclose(fp);

for(i=1,k=1;i<=128;i++)

{

if(s1[i].num!

=0)

{

s2[k].num=s1[i].num;

s2[k].data=s1[i].data;

k++;

}

}

printf("\n\n统计结果为(字符频率):

\n");

for(i=1;i

{

printf("<%c%d>",s2[i].data,s2[i].num);

}

printf("(共%d种字符)\n",k-1);

returnk;

}

voidSelectMin(HuffmanTreeht,inti,int*p1,int*p2)//查找哈夫曼链表中两个权值最小的节点

{

intj,min1,min2;

min1=min2=-1;

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

{

if(ht[j].parent==0)

{

if(ht[j].weight

{

if(min1!

=-1)

{min2=min1;*p2=*p1;}

min1=ht[j].weight;*p1=j;

}

elseif(ht[j].weight

{

min2=ht[j].weight;

*p2=j;

}

}

}

}

voidCrtHuffmanTree(HuffmanTreeht,strs[],intn)//创建哈夫曼树

{

inti,m,p1,p2;

for(i=1;i

{

ht[i].data=s[i].data;

ht[i].weight=s[i].num;

ht[i].parent=0;

ht[i].lchild=0;

ht[i].rchild=0;

}

m=2*n-3;

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

{

ht[i].data=0;

ht[i].weight=0;

ht[i].parent=0;

ht[i].lchild=0;

ht[i].rchild=0;

}

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

{

SelectMin(ht,i-1,&p1,&p2);//调用SelectMin函数

ht[i].weight=ht[p1].weight+ht[p2].weight;

ht[p1].parent=i;ht[p2].parent=i;

ht[i].lchild=p1;ht[i].rchild=p2;

}

}

voidCrtHuffmanCode(HuffmanTreeht,HuffmanCodehc,intk)//利用建立好的哈夫曼树对字符串进行编码

{

intc,p,i;

charcd[N+1];

intstart;

for(i=1;i

{

hc[i].data=ht[i].data;

start=k-1;

cd[start]='\0';

c=i;

while((p=ht[c].parent)!

=NULL)

{

cd[--start]=(ht[p].lchild==c)?

'0':

'1';//左分支为0,右分支为1

c=p;

}

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

}

printf("\n\n每个字符对应的编码为:

\n");

for(i=1;i

printf("<%d%c%s>\n",i,hc[i].data,hc[i].bits);

}

voidWriteToFile(HuffmanCodehc,intn)//将编码结果存储在文件文件ywq2.txt中

{

FILE*fp1,*fp2;

charch;

inti;

if((fp1=fopen("ywq1.txt","r"))==NULL)

{

printf("\n文件不存在!

");

exit

(1);

}

if((fp2=fopen("ywq2.txt","w"))==NULL)

{

printf("\n文件不存在!

");

exit

(1);

}

ch=fgetc(fp1);

printf("\n编码结果为:

");

while(ch!

=EOF)

{

for(i=1;i

if(ch==hc[i].data)

{

fputs(hc[i].bits,fp2);

printf("%s",hc[i].bits);

}

ch=fgetc(fp1);

}

fclose(fp1);

fclose(fp2);

printf("\n");

}

voidDecodHuffmanCode(HuffmanTreeht,intn)//码结果进行译码,并将结果存储在文件ywq3中

{

FILE*fp1,*fp2;

charch;

intp,k;

if((fp1=fopen("ywq2.txt","r"))==NULL)

{

printf("\n文件不存在!

");

exit

(1);

}

if((fp2=fopen("ywq3.txt","w"))==NULL)

{

printf("\n文件未能创建!

");

exit

(1);

}

p=k=2*n-3;

ch=fgetc(fp1);

printf("译码为:

");

while(ch!

=EOF)

{

if(ch=='0')p=ht[p].lchild;

elseif(ch=='1')p=ht[p].rchild;

if(ht[p].data!

=0)

{

printf("%c",ht[p].data);

fputc(ht[p].data,fp2);

p=k;

}

ch=fgetc(fp1);

}

printf("\n");

fclose(fp1);fclose(fp2);

}

voidcompare(intk)

{

FILE*fp1,*fp2;

chars1[N],s2[N];

inti=1,j=1;

printf("\n\n编译前后结果的比较:

");

if((fp1=fopen("ywq1.txt","rt"))==NULL)

{

printf("\n打开文件失败!

\n");

exit

(1);

}

printf("\n\n原文件ywq1中的字符为:

");

for(i=1;(s1[i]=fgetc(fp1))!

=EOF;i++)

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

fclose(fp1);

if((fp2=fopen("ywq3.txt","rt"))==NULL)

{

printf("\n打开文件失败!

\n");

exit

(1);

}

printf("\n文件ywq3中的字符为:

");

for(i=1;(s2[i]=fgetc(fp2))!

=EOF;i++)

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

fclose(fp2);

while(j

{

if(s1[j]==s2[j])

j++;

else

{

printf("\n编码失败!

\n");

break;

}

}

if(j==k)

printf("\n前后数据一致,编码成功!

\n");

}

voidmain()

{

inti,k;

intj=1;

HuffmanTreeht;

HuffmanCodehc;

strs2[128];

printf("\n-------------------------------哈夫曼编码译码器---------------------------------");

k=read(s2);

getchar();

CrtHuffmanTree(ht,s2,k);

CrtHuffmanCode(ht,hc,k);

WriteToFile(hc,k);

getchar();

printf("\n\n");

printf("建立的哈夫曼树为:

");

printf("\nnumber\tdata\tweight\tlchild\trchild\tparent");

for(i=1;i

{

printf("\n%d:

%c%d%d%d}

printf("\n\n");

DecodHuffmanCode(ht,k);

getchar();

compare(k);

//printf("\n\n按任意键退出...\n");

}

2、运行结果

注意:

在运行的时候,一直按【Enter】键执行

 

六、调试分析

1.测试的结果

请参考上面的运行结果。

2.时间复杂度分析

构造赫夫曼树:

T(n)=O(n)

建立赫夫曼表:

T(n)=O(n2)

进行译码:

T(n)=O(n)

赫夫曼编码T(n)=O(n³)

3.各模块在设计和调试时存在问题

a、怎样把一篇文章英语文章的字符个数统计出来,并且把权值给统计出来,最后是用什么来存储。

b、建立赫夫曼树,先找到权值最小的两个字符建立成赫夫曼树,并且写出赫夫曼码。

c、最大的难题是怎么把文本用赫夫曼码代替,就是把英语文章翻译成赫夫曼码,就是所谓的译码过程。

d、将译码后的文章打印出来

4.算法的改进设想

在这个算法中我觉得有个地方要改进,就是在编译和反编译的过程中,存储的那些赫夫曼码和英语文章在每次执行之后没有自己清除,我觉得这个地方要改进,还有一点这个算法在时间复杂度上面有点复杂,但是我没有找到好的方法,这是我觉得这个算法要改进的地方

七、设计心得和总结

八、参考书籍

《数据结构理论与实践》杨永斌.主编天津科学技术出版社

 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 历史学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1