信息论实习报告Word文件下载.docx
《信息论实习报告Word文件下载.docx》由会员分享,可在线阅读,更多相关《信息论实习报告Word文件下载.docx(33页珍藏版)》请在冰豆网上搜索。
{
low=Low;
high=Low+chance[j]*d;
High=high;
d*=chance[j];
}
else
doublechance_l=0.0;
for(intk=0;
k<
=j-1;
k++)
chance_l+=chance[k];
low=Low+d*chance_l;
high=Low+d*(chance_l+chance[j]);
Low=low;
}
}
else
continue;
}
2)计算码长
for(inti=0;
for(intj=0;
if(code[i]==number[j])
sum*=chance[i];
intL=(int)log(1.00/sum);
3)求最终编码
for(inti=0;
L;
{
Low*=2;
if(Low>
1)
cout<
<
1;
Low-=1;
else
cout<
0;
7.3程序运行结果
输入信源符号及对应的概率分布:
输入符号序列:
得到相应的结果:
该数据来源为课件。
7.4、程序分析
在网上下的程序并未对码长以及最终编码进行计算和输出,根据可见所讲,将信息熵求出后计算了码长,并输出了最后的编码结果。
重新认识了算术编码的编码过程,对于解码部分,并未做相应的编程实现。
但是了解了其解码过程,虽然对能否无损解码持怀疑态度。
八、源代码
#include<
iostream>
usingnamespacestd;
math.h>
#defineM100
#defineN4
classsuanshu
{
intcount,length;
charnumber[N],n;
longdoublechance[N],c;
charcode[M];
longdoubleHigh,Low,high,low,d;
public:
suanshu()
{High=0;
Low=0;
}
voidget_number();
voidget_code();
voidcoding();
voidprint();
~suanshu(){};
};
voidsuanshu:
:
get_number()
cout<
"
输入信源符号及其对应概率:
endl;
inti;
longdoublesum=0.00;
for(i=0;
N&
&
sum<
=1;
cin>
>
n>
c;
number[i]=n;
chance[i]=c;
sum+=c;
if(i==20)
cout<
信源符号数溢出."
if(sum>
概率和超过."
count=i;
get_code()
输入符号序列长:
;
cin>
length;
while(length>
=M)
输入的符号序列超长,请改小!
cin>
for(inti=0;
i<
i++)
code[i];
coding()
{
inti,j=0;
for(i=0;
count;
if(code[0]==number[i])
break;
while(j<
i)
Low+=chance[j++];
d=chance[j];
High=Low+d;
print()
算数编码结果为:
Low<
二进制结果:
doublesum=1.00;
for(inti=0;
for(inti=0;
voidmain()
suanshua;
a.get_number();
a.get_code();
a.coding();
a.print();
实验四Huffman编码对英文文本的压缩和解压缩
一、实验内容
根据信源压缩编码——Huffman编码的原理,制作对英文文本进行压缩和解压缩的软件。
要求软件有简单的用户界面,软件能够对运行的状态生成报告,分别是:
字符频率统计报告、编码报告、压缩程度信息报告、码表存储空间报告。
4.计算机
5.Windows2000或以上
6.MicrosoftOffice2000或以上
7.VS2005
3.掌握Huffman编码的原理
4.掌握VC开发环境的使用(尤其是程序调试技巧)
5.掌握C语言编程(尤其是位运算和文件的操作)
6.掌握数据结构的内容:
链表、顺序表、堆栈、最优二叉树
7.掌握结构化程序分析和开发的软件工程原理
4.提前预习实验,认真阅读实验原理。
5.认真高效的完成实验,实验过程中服从实验室管理人员以及实验指导老师的管理。
6.认真填写实验报告。
压缩/解压缩流程
压缩流程:
读取扫描文本文件——〉统计字符频率——〉生成码字——〉保存压缩文件
解压缩流程:
读取扫描压缩文件——〉提取字符频率——〉生成码树——〉保存文本文件
2.《信息论——基础理论及应用》傅祖芸,电子工业出版社
3.《数据结构》,清华大学出版社
7.1数据结构描述:
以下是哈夫曼树结点的结构:
//哈夫曼树结点结构体实现
typedefstructtalNode{
unsignedcharc;
//叶结点时对应ASCII值
intweight;
//该结点权值
intlt,rt;
//左、右结点下标
talNode(){}
talNode(unsignedchar_c,int_p):
c(_c),weight(_p),lt(-1),rt(-1)
{}
talNode(unsignedchar_c,int_p,intl,intr)
:
c(_c),weight(_p),lt(l),rt(r)
booloperator<
(talNodea)
{//重载运算符“<
”用于二叉堆内的比较
returnweight<
a.weight;
}HuffNode;
哈夫曼树以数组形式保存,其元素个数是2n-1,其中n为叶子数。
对应结点的哈夫曼编码用一个数组记录,该数组元素是指向字符的指针
7.2主要算法描述
7.2.1压缩
其基本实现方法是,因为英文文件中都是ACSII码(包括英文的标点符号),所以对选定的文件文本读入,一次读入一个字符,然后对每个ASCII字符进行统计,如此循换,这就统计出文件的每个字符的权值了。
得出文件各字节的权值后,就可以构造对应哈夫曼的哈夫曼树,从而就可以构造出对应字符的哈夫曼编码了。
每个字符的哈夫曼编码都知道了,那么文件的哈夫曼编码就可以求出了。
7.2.2关于解压
解压时,先读出哈夫曼编码的节点及其权值,然后对编码部分读取一个字节(8bit)用一个函数转换为8个字符(用一个数组记录,其元素只是一个0或一个1),然后按哈夫曼树从顶向下查找,如果到达叶子结点,就读出该叶子结点的值,放入缓冲区中,如果不是,则继续找,如此重复,直到缓冲区满了,就写入到解压文件中,再循环以上过程,直到处理完所有数据。
7.3具体函数设计
7.3.1压缩函数设计
点击压缩后,调用压缩函数EnCodeFile()
SaveHuffHead(fpt);
//写入压缩文件的头信息!
!
注意,此时lastcodelenth为空,需压缩结束时重置
l=data=0;
puts("
Encoding..."
);
//编码压缩过程,依次对源文件字符进行编码
while(true){//存入一个字符中,用移位操作实现,每位前
c=fgetc(fp);
//缀码对应一个字符,将该字符存入目标文件,
if(feof(fp))break;
//最终不足位的记录最后一位占用的前缀码长度
soucelen++;
//源文件长度增加
for(i=0;
lenth[c];
i++){//对data进行左移,空出最低位
data<
=1;
//对当前字符的前缀码当前们存储于data中
data+=code[c][i];
if(++l%8==0){//满位,则存储
fputc(data,fpt);
targetlen++;
//目标文件长度增加
}//对最后的一个字符进行处理
lastcodelenth=l%8;
//记录实际占用位的长度
data<
=8-lastcodelenth;
//空出剩余位
fputc(data,fpt);
//输出至文件
targetlen++;
//目标文件长度增加
该函数主要是涉及三个步骤:
构造哈夫曼树、构造哈弗曼编码、压缩。
7.3.2解压函数设计
点击解压后,调用解压函数DeCodeFile()
DeCodePre(fp);
l=0;
Decoding..."
fscanf(fp,"
%c"
&
c);
//解码过程,压缩过程的逆过程,取出编码了的字符,
//按位取出,存于tmp[]中,找出前缀码对应的字符
while(!
feof(fp)){
fscanf(fp,"
t);
if(feof(fp))break;
for(i=l+7;
i>
=l;
i--){//按位取出前缀码
tmp[i]=c&
1;
c>
}l+=8;
while(l>
=32){//如果当前前缀码段超出一定的长度,则取出前缀码进行解码
for(i=0,cur=arr[size-1];
cur.c;
cur=tmp[i]?
arr[cur.rt]:
arr[cur.lt];
//找到前缀码段对应第一个字符
fprintf(fpt,"
cur.c);
//输出至目标文件
l-=i;
targetlen++;
//前缀码段减去当前字符前缀码长度
memmove(tmp,tmp+i,sizeof(bool)*l);
//数组顺移至开头,即从开始记录当前的前缀码段
}c=t;
for(i=l+7;
i--){//对最后一个字符做特殊处理
tmp[i]=c&
//取出每一位
c>
l+=lastcodelenth;
//只利用最后一个字符的前lastcodelenth位
while(l){//输出剩余的前缀码段对应的字符
for(i=0,cur=arr[size-1];
cur=tmp[i]?
fprintf(fpt,"
l-=i;
memmove(tmp,tmp+i,sizeof(bool)*l);
fclose(fp);
fclose(fpt);
//关闭文件
7.4程序体验
7.4.1程序界面:
7.4.2选择文件并压缩:
源文件“test.txt”的内容
选取文件
压缩完成
选择的源文件为:
“D:
\我的文档\test.txt”压缩后的文件存储在相同路径下,压缩后的文件名:
“test.huf”,文件长度减小了7908。
其内容为下:
压缩后的内容
7.4.3解压
选择刚才的压缩文件进行解压:
解压成功
解压后的文件名为:
“test.txt”
解压后的文件内容
经过压缩解压后得到的文件内容和压缩前的一致。
利用MD5比较,得到压缩前文件与解压得到的文件为同一文件。
DE01E3358BCA716ACB444661E862CBDD
Huffman.h:
#pragmaonce
//***************************************************************
//课程:
信息论与编码
//题目:
霍夫曼编码实现文本压缩解压
//老师:
余林琛
//作者:
刘宇豪
//时间:
-11-2
#include<
stdlib.h>
#include"
stdafx.h"
#defineASCIIL256
#defineF(x)((x-1)>
1)
#defineL(x)((x<
1)+1)
#defineR(x)((x<
1)+2)
#defineSWAP(a,b,tmp){tmp=a;
a=b;
b=tmp;
//实现二叉堆模板类,小顶堆
template<
classHeapType>
classCHeap
HeapType*data,tmp;
intsize;
voidHeapUp(intix)
{//自底向顶维护堆
intf;
for(f=F(ix);
ix&
data[ix]<
data[f];
ix=f,f=F(f))
SWAP(data[ix],data[f],tmp);
voidHeapDown(intix)
{//自顶向底维护堆
intl,r,t;
HeapTypemin,tmp;
if(ix>
=size)return;
l=L(ix),r=R(ix);
min=data[ix],t=ix;
if(l<
size&
data[l]<
min)
t=l,min=data[l];
if(r<
data[r]<
t=r,min=data[l];
SWAP(data[ix],data[t],tmp);
if(ix!
=t)HeapDown(t);
CHeap()
{//这里特殊应用,堆内元素个数不超过
size=0;
data=newHeapType[256];
~CHeap()
{//释放内存
deletedata;
intgetsize()
{//返回堆大小
returnsize;
voidclear()
{//清空堆
voidinsert(HeapTypee)
{//向堆尾中插入元素,并向顶维护堆
data[size++]=e;
HeapUp(size-1);
HeapTypetop()
{//从堆顶取出元素,并向底维护堆
HeapTyperet=data[0];
data[0]=data[--size];
HeapDown(0);
returnret;
classCHuffMan{
HuffNodearr[512];
//哈夫曼树结点数组
//哈夫曼树结点个数
boolcode[256][64];
//ASCII对应编码方案
intlenth[256];
//ASCII对应编码长度
//lastcodelenth,ps[256],用于存储压缩文件中作为文件头
intlastcodelenth;
//文件最后一个字符实用几位
intps[256];
//ASCII对应出现频率
intsoucelen,targetlen;
//源及目标文件长度
//私有成员函数,用于实现内部功能
voidSetHuffTree(int[]);
//根据字符频率生成哈夫曼树
voidSetHuffCode(int,bool[],int);
//根据哈夫曼树生成编码方案
voidCreateHuff(int[]);
//创建哈夫曼树及编码方案
voidEnCodePre(CString);
//压缩前预处理
voidDeCodePre(FILE*);
//解压前预处理
voidSaveHuffHead(FILE*);
//保存压缩文件头
voidReadHuffHead(FILE*);
//读取压缩文件头
CHuffMan(){Clear();
}//构造函数
~CHuffMan(){}//析构函数
//公有成员函数,用于提供使用接口
voidClear();
//清空当前对象内容
voidEnCodeFile(CString,CString);
//编码,用于压缩文件,第一个参数为源文件名,第二个参数为目标文件名
voidDeCodeFile(CString,CString);
//解码