记信息论与编码之课设-哈夫曼编码
来源:互联网 发布:金融互助系统源码 编辑:程序博客网 时间:2024/05/20 16:34
哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,
夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)
首先,将符号按照概率由大到小排队,编码时,从最小概率的两个符号开始,可选其中一个支路为0,另一支路为1。这里,我们选上支路为0,下支路为1。再将已编码的两支路的概率合并,并重新排队。多次重复使用上述方法直至合并概率归一时为止。
从文件中或者输入 读入一个字符串,统计字符串中的字符种类(不包括大小写),以及每个字符出现的概率,并按照霍夫曼编程思想,构造哈夫曼树结构,将其转化成“01”的二进制字符串,并且可以读入一串01字符串,将其译为对应的哈夫曼字符。并计算其编码效率。
基本算法:① 输入字符串 (不包含大小写),回车结束
② 根据循环遍历统计字符串中每个不同字符的概率以及总个数
③ 根据哈夫曼编码构造哈夫曼树
先将数组排序,采用优先队列求出最小的两个概率,求和得到父节点 ,加入哈夫曼树数组中,依次循环直到只剩下一个概率且为1的根节点
④ 编码,从每个叶子节点向根遍历,如果是左子树编码就为0,右子树为1.直到所有的叶子节点都编码完毕。
⑤ 根据公式求编码效率n == H(s)/l;
⑥ 译码 ,根据输入的字符串,从根节点开始想下边遍历,如果是1就向右子树,0就是左子树,直到找到一个叶子节点就退出。继续从根节点开始。
代码如下:#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<queue>#include<stack>#include<cmath>#include<algorithm>#include<functional>#define max 200using namespace std;struct jcode//求得概率之后的结构体{ char c; int x;//概率 int b;//下标 friend bool operator<(jcode a, jcode b ){//优先队列排序 return b.x<a.x; }};typedef jcode jjnum[max];typedef struct bnode{//存储哈夫曼树的结构体数组 char data; int x; int lchild,rchild,parent; char code[max];//每个字符编码 int len;//编码长度}bnode;typedef bnode huffman[max];//统计输入的字符及各自概率int getnum(string ss,jjnum str){ int i,j; int temp[max]; for(i = 0;i< max;i++) { temp[i]=0; } for(i = 0;i<ss.length();i++)//求概率 temp[ss[i]-'!']++; j=0; for(i = 0;i<max;i++)//存到结构体1 { if(temp[i]!=0) { str[j].x= temp[i]; str[j].c = i+'!'; str[j].b = j; j++; } } return j;}void create(priority_queue<jcode>q,huffman &t,int cnum,jjnum str)//构造哈夫曼树{ int i,a1,a2; for(i=0;i<2*cnum-1;i++)//初始化结点 { t[i].lchild = t[i].parent = t[i].rchild = t[i].x = 0; t[i].data= '1'; } for(i=0;i<cnum;i++)//叶子节点 { t[i].x = str[i].x; t[i].data = str[i].c; } for(i=cnum;i<2*cnum-1;i++)//根据哈夫曼编码构造哈夫曼树 { a1 = q.top().b; t[a1].parent = i;q.pop(); a2 = q.top().b; t[a2].parent = i;q.pop(); t[i].lchild = a1;//指向孩子 t[i].rchild = a2; t[i].x = t[a1].x+t[a2].x;//概率小的两个相加 jcode e; e.c = '1';e.x = t[i].x;e.b = i; q.push(e);//和存到队列中 } for(i=0;i<cnum;i++)//由0.1进行二元编码,1右0左 { int x; x=i; t[i].len = 0; while(t[x].parent!=0)//从叶子节点向根 { if(t[t[x].parent].lchild == x) { t[i].code[t[i].len]='0';//存下来编码 t[i].len++; } else { t[i].code[t[i].len]='1'; t[i].len++; } x = t[x].parent; } } for(i=0;i<cnum;i++)//输出每个字符编码 { if(t[i].data!='1') { cout<<t[i].data<<" === "; for(int j=t[i].len-1;j>=0;j--) cout<<t[i].code[j]; cout<<endl; } }}//编码fvoid strhttree(jjnum str,int num,huffman &t){ int i; priority_queue<jcode>q2; for(i = 0; i < num; i++)//加入优先队列 q2.push(str[i]); create(q2,t,num,str);}void yima(string ss,int i,huffman &t,int num,int cnum)//译码{ while(num>=cnum)//从根节点开始 { if(ss[i]=='1') { num = t[num].rchild; i++; } else { num = t[num].lchild; i++; } } if(i<=ss.length())//得到一个叶子节点,即译出一个字符 { cout<<t[num].data; yima(ss,i,t,2*cnum-2,cnum);//继续译码 }}int main(){ string s;//输入字符串 huffman t;//哈夫曼树 getline(cin,s); jcode str[max]; int cnum = getnum(s,str);//字符的种类个数 strhttree(str,cnum,t);//构造哈夫曼树 for(int k = 0;k<s.length();k++)//输出编码 for(int i=0;i<cnum;i++) { if(s[k]==t[i].data){ for(int j=t[i].len-1;j>=0;j--) cout<<t[i].code[j]; } } cout<<endl; double sum1 =0.0,sum2 = 0.0; for(int i = 0;i<cnum;i++)//求编码效率 { sum1+=((t[i].x*1.0/s.size())*(-log2(t[i].x*1.0/s.size()))); sum2+=(t[i].x*1.0/s.size())*t[i].len; } cout<<"n=="<<(sum1/sum2)<<endl; string l; getline(cin,l);//输入码 int x= 2*cnum -2;//根节点、 yima(l,0,t,x,cnum);//译码 return 0;}
- 记信息论与编码之课设-哈夫曼编码
- 信息论之哈夫曼编码
- 信息论与编码之算术编码
- 信息论与编码复习
- 信息论与编码 上机
- 信息论与编码题库
- 哈夫曼编码课设
- 信息论与编码相关知识点
- DES 算法 信息论与编码
- 《信息论与编码》学习笔记
- 信息论与编码 学习笔记(一)
- 赫夫曼编码课设
- 信息论编码发展
- 信息论的编码
- 谈谈编码 | 信息论
- 信息论实验-Hamming编码
- 我用过的信息论与编码教材
- 信息论与编码——密码史的发展
- 在CentOS上升级Python的坑
- 微信开发整合日记(2)
- Linux系统Mysql5.6安装
- POJ 1006 Biorhythms
- 机器学习笔记(一)-局部加权回归(Locally weighted regression)LWR
- 记信息论与编码之课设-哈夫曼编码
- 几种常见的继承
- Java网络编程总结
- 必备工具
- SpringMVC的四个基本注解annotation
- imooc js进阶篇 6-11编程练习
- Windows文本文件编码
- VB的PaintPicture与StretchBlt的异同比较
- 136. Single Number