北邮 数据结构 哈夫曼树报告.docx
《北邮 数据结构 哈夫曼树报告.docx》由会员分享,可在线阅读,更多相关《北邮 数据结构 哈夫曼树报告.docx(11页珍藏版)》请在冰豆网上搜索。
北邮数据结构哈夫曼树报告
数据结构
实
验
报
告
实验名称:
哈夫曼树
学生:
袁普
班级:
2013211125班
班序号:
14号
学号:
2013210681
日期:
2014年12月
1.
实验目的和容
利用二叉树结构实现哈夫曼编/解码器。
基本要求:
1、初始化(Init):
能够对输入的任意长度的字符串s进行统计,统计每个字符的频度,
并建立哈夫曼树
2、建立编码表(CreateTable):
利用已经建好的哈夫曼树进行编码,并将每个字符的编码输出。
3、编码(Encoding):
根据编码表对输入的字符串进行编码,并将编码后的字符串输
出。
4、译码(Decoding):
利用已经建好的哈夫曼树对编码后的字符串进行译码,并输出
译码结果。
5、打印(Print):
以直观的方式打印哈夫曼树(选作)
6、计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫曼编码的压
缩效果。
7、可采用二进制编码方式(选作)
测试数据:
IlovedataStructure,IloveComputer。
IwilltrymybesttostudydataStructure.
提示:
1、用户界面可以设计为“菜单”方式:
能够进行交互。
2、根据输入的字符串中每个字符出现的次数统计频度,对没有出现的字符一律不用编码
2.程序分析
2.1存储结构
用struct结构类型来实现存储
树的结点类型
structHNode
{
intweight;//权值
intparent;//父节点
intlchild;//左孩子
intrchild;//右孩子
};
structHCode//实现编码的结构类型
{
chardata;//被编码的字符
charcode[100];//字符对应的哈夫曼编码
};
2.2程序流程
输入字符串
统计出现的字符种类和次数,构建权值数组,初始化树结点与编码表
根据哈夫曼构建规则构建哈夫曼树,根据编码规则对出现字符进行编码,构建编码表
将输入的字符挨个编码
对编码后的字符进行解码
分析存储大小
2.3关键算法分析
算法1:
voidHuffman:
:
Count()
[1]算法功能:
对出现字符的和出现字符的统计,构建权值结点,初始化编码表
[2]算法基本思想:
对输入字符一个一个的统计,并统计出现次数,构建权值数组,
[3]算法空间、时间复杂度分析:
空间复杂度O
(1),要遍历一遍字符串,时间复杂度O(n)
[4]代码逻辑:
leaf=0;//初始化叶子节点个数
inti,j=0;
ints[128]={0};用于存储出现的字符
for(i=0;str[i]!
='\0';i++)遍历输入的字符串
s[(int)str[i]]++;统计每个字符出现次数
for(i=0;i<128;i++)
if(s[i]!
=0)
{
data[j]=(char)i;给编码表的字符赋值
weight[j]=s[i];构建权值数组
j++;
}
leaf=j;//叶子节点个数即字符个数
for(i=0;icout<"<算法2:
voidInit();
[1]算法功能:
构建哈弗曼树
[2]算法基本思想:
根据哈夫曼树构建要求,选取权值最小的两个结点结合,新结点加入数组,再继续选取最小的两个结点继续构建。
[3]算法空间、时间复杂度分析:
取决于叶子节点个数,时间复杂度O(n),空间复杂度O
(1)
[4]代码逻辑
HTree=newHNode[2*leaf-1];n2=n0-1,一共需要2n-1个结点空间
for(inti=0;i{
HTree[i].weight=weight[i];给每个结点附权值
HTree[i].lchild=-1;初始化左右孩子和父节点,都为-1
HTree[i].rchild=-1;
HTree[i].parent=-1;
}
intx,y;//用于记录两个最小权值
for(inti=leaf;i<2*leaf-1;i++)
{
Selectmin(HTree,i,x,y);选出两个最小权值的结点
HTree[x].parent=i;父节点设置为新建立的结点
HTree[y].parent=i;
HTree[i].weight=HTree[x].weight+HTree[y].weight;父节点权值为两个相加
HTree[i].lchild=x;使父节点指向这两个孩子结点
HTree[i].rchild=y;
HTree[i].parent=-1;父节点的父节点设为-1
}
算法3:
voidSelectmin(HNode*hTree,intn,int&i1,int&i2);
[1]算法功能:
从现有的结点中选择出两个最小的结点,返回其位置
[2]算法基本思想:
先选出两个没有构建的结点,然后向后依次比较,筛选出最小的两个结点
[3]算法空间、时间复杂度分析:
空间复杂度O
(1),要遍历所有结点,时间复杂度O(N)
[4]代码逻辑
inti;
for(i=0;i{
if(hTree[i].parent==-1)//父节点不是-1意味着这个结点还没有被选择过
{
i1=i;记录结点位置
break;
}
}
i++;//执行一遍for循环就加1,意为下次查找从当前位置开始查找
for(;i{
if(hTree[i].parent==-1)
{
i2=i;记录第二个没选择过的结点编号
break;
}
}
if(hTree[i1].weight>hTree[i2].weight)进行比较,使I1为最小的,I2为第二小的
{
intj=0;
j=i2;
i2=i1;
i1=j;
}
i++;
for(;i{
if(hTree[i].parent==-1&&hTree[i].weight{
i2=i1;使I2=I1I1=新结点
i1=i;
}
elseif(hTree[i].parent==-1&&hTree[i].weight{I1《新结点《I2,使I2为新节点
i2=i;
}
}
算法4:
voidCreateTable();
[1]算法功能:
对出现的字符进行编码
[2]算法基本思想:
根据字符在哈夫曼树中的位置,从下到上编码,是左孩子编0,右孩子编1
[3]算法空间、时间复杂度分析:
空间复杂度O
(1),要遍历data数组,时间复杂度0(N)
[4]代码逻辑
HCodeTable=newHCode[leaf];新建编码结点,个数为叶子节点个数
for(inti=0;i{
HCodeTable[i].data=data[i];
intchild=i;初始化要编码的结点的位置
intparent=HTree[i].parent;初始化父结点
intk=0;//统计编码个数
while(parent!
=-1)
{
if(child==HTree[parent].lchild)
HCodeTable[i].code[k]='0';//左孩子标‘0’
else
HCodeTable[i].code[k]='1';//右孩子标‘1’
k++;
child=parent;孩子结点上移
parent=HTree[child].parent;父节点也上移
}
HCodeTable[i].code[k]='\0';//将编码反向
charcode[100];
for(intu=0;ucode[u]=HCodeTable[i].code[k-u-1];
for(intu=0;uHCodeTable[i].code[u]=code[u];
cout<";
cout<length3[i]=k;//每一个字符编码的长度,为求编码总长度做准备
}
算法5:
voidEncoding();
[1]算法功能:
对输入的字符串进行编码
[2]算法基本思想:
找到每个字符对应的编码,将编码按顺序输出
[3]算法空间、时间复杂度分析:
空间复杂度O
(1),时间复杂度0(n)
[4]代码逻辑
cout<"<for(inti=0;str[i]!
='\0';i++)遍历输入的每一个字符
{
for(intj=0;jif(str[i]==HCodeTable[j].data)找到字符对应的编码
{s1=s1+HCodeTable[j].code;将所有编码按顺序加起来
cout<}
}
cout<算法6:
voidDecoding();
[1]算法功能:
对编码串进行解码
[2]算法基本思想:
找到每段编码对应的字符,输出字符
[3]算法空间、时间复杂度分析:
时间复杂度0(N),空间复杂度0
(1)
[4]代码逻辑(可用伪代码描述)
cout<<"解码后的字符串为:
"<char*s=const_cast(s1.c_str());将编码字符串转化为char
while(*s!
='\0')
{
intparent=2*leaf-2;父节点为最后一个节点
while(HTree[parent].lchild!
=-1)//还有左子树,不可能是叶子节点
{
if(*s=='0')编码为0,为左孩子
parent=HTree[parent].lchild;
else
parent=HTree[parent].rchild;编码为1,为右孩子
s++;
}
cout<}
cout<……
注意分析程序的时间复杂度、存申请和释放,以及算法思想的体现。
2.4其他
在此次试验中使用了类和STL中的string,使用string可以方便的将单个字符的编码加起来成为总的编码后的数值,再利用STL中的转化函数可以直接将string转化为char,方便进行解码工作。
总而言之,使用STL使得编码大大的简洁了。
3.程序运行结果分析
调试过程中遇到的问题主要是执行时有存错误,检查后发现是数组有越界现象,这提醒我在编写时一定要仔细,特别是在for循环条件上一定要注意围
总结
4.1实验的难点和关键点
首先在输入字符串时我发现直接用cin无法输入空格,在上网查询后找到了getline函数解决了这个问题。
然后还有就是如何存储编码后总的那个字符串,因为每一个字符编码的长度不定,无法用char数组来存储,于是用了string的相加函数来将所有编码加起来。
最后由于在解码时要用char数组,又上网查询到了string转化成char的函数解决了这个问题,实验难点也在于如何找到两个最小权值来构建哈夫曼树,寻找两个最小权值的思想主要是通过一个个的比较来找到最小值,而且注意形参要用引用。
4.2心得体会
通过此次实验我体会到了stl的优越性。
还有就是编码时要注意数组的大小。
再者就是有问题时可以试着去网上查询答案。