和Huffman-Tree一样,Shannon-Fano coding也是用一棵二叉树对字符进行编码。但在实际操作中呢,Shannon-Fano却没有大用处,这是由于它与Huffman coding相比,编码效率较低的结果(或者说香农-范诺算法的编码平均码字较大)。但是它的基本思路我们还是可以参考下的。

根据Wikipedia上面的解释,我们来看下香农范诺算法的原理:

Shannon-Fano的树是根据旨在定义一个有效的代码表的规范而建立的。实际的算法很简单:

  1. 对于一个给定的符号列表,制定了概率相应的列表或频率计数,使每个符号的相对发生频率是已知。
  2. 排序根据频率的符号列表,最常出现的符号在左边,最少出现的符号在右边。
  3. 清单分为两部分,使左边部分的总频率和尽可能接近右边部分的总频率和。
  4. 该列表的左半边分配二进制数字0,右半边是分配的数字1。这意味着,在第一半符号代都是将所有从0开始,第二半的代码都从1开始。
  5. 对左、右半部分递归应用步骤3和4,细分群体,并添加位的代码,直到每个符号已成为一个相应的代码树的叶。

示例

香农-范诺编码算法

这个例子展示了一组字母的香浓编码结构(如图a所示)这五个可被编码的字母有如下出现次数:

Symbol A B C D E
Count 15 7 6 6 5
Probabilities 0.38461538 0.17948718 0.15384615 0.15384615 0.12820513

从左到右,所有的符号以它们出现的次数划分。在字母B与C之间划定分割线,得到了左右两组,总次数分别为22,17。 这样就把两组的差别降到最小。通过这样的分割, A与B同时拥有了一个以0为开头的码字, C,D,E的码子则为1,如图b所示。 随后, 在树的左半边,于A,B间建立新的分割线,这样A就成为了码字为00的叶子节点,B的码子01。经过四次分割, 得到了一个树形编码。 如下表所示,在最终得到的树中, 拥有最大频率的符号被两位编码, 其他两个频率较低的符号被三位编码。

符号 A B C D E
编码 00 01 10 110 111

Entropy(熵,平均码字长度): 

Pseudo-code

1:  begin2:     count source units3:     sort source units to non-decreasing order4:     SF-SplitS5:     output(count of symbols, encoded tree, symbols)6:     write output7:   end8:  9:  procedure SF-Split(S)
10:  begin
11:     if (|S|>1) then
12:      begin
13:        divide S to S1 and S2 with about same count of units
14:        add 1 to codes in S1
15:        add 0 to codes in S2
16:        SF-Split(S1)
17:        SF-Split(S2)
18:      end
19:  end

想不清楚的朋友可以看下这个网站的模拟程序,很形象,perfect~

香农-范诺算法实现(Shannon-Fano coding implementation in C++)

我们由上面的算法可知,需要迭代地寻找一个最优点,使得树中每个节点的左右子树频率总和尽可能相近。
这里我寻找最优化点用的是顺次查找法,其实呢,我们还可以用二分法(dichotomy)达到更高的效率~
[cpp] view plaincopy
  1. /************************************************************************/
  2. /*  File Name: Shanno-Fano.cpp
  3. *       @Function: Lossless Compression
  4. @Author: Sophia Zhang
  5. @Create Time: 2012-9-26 20:20
  6. @Last Modify: 2012-9-26 20:57
  7. */
  8. /************************************************************************/
  9. #include"iostream"
  10. #include "queue"
  11. #include "map"
  12. #include "string"
  13. #include "iterator"
  14. #include "vector"
  15. #include "algorithm"
  16. #include "math.h"
  17. using namespace std;
  18. #define NChar 8 //suppose use 8 bits to describe all symbols
  19. #define Nsymbols 1<<NChar //can describe 256 symbols totally (include a-z, A-Z)
  20. #define INF 1<<31-1
  21. typedef vector<bool> SF_Code;//8 bit code of one char
  22. map<char,SF_Code> SF_Dic; //huffman coding dictionary
  23. int Sumvec[Nsymbols];   //record the sum of symbol count after sorting
  24. class HTree
  25. {
  26. public :
  27. HTree* left;
  28. HTree* right;
  29. char ch;
  30. int weight;
  31. HTree(){left = right = NULL; weight=0;ch ='\0';}
  32. HTree(HTree* l,HTree* r,int w,char c){left = l; right = r;  weight=w;   ch=c;}
  33. ~HTree(){delete left; delete right;}
  34. bool Isleaf(){return !left && !right; }
  35. };
  36. bool comp(const HTree* t1, const HTree* t2)//function for sorting
  37. {   return (*t1).weight>(*t2).weight;    }
  38. typedef vector<HTree*> TreeVector;
  39. TreeVector TreeArr;//record the symbol count array after sorting
  40. void Optimize_Tree(int a,int b,HTree& root)//find optimal separate point and optimize tree recursively
  41. {
  42. if(a==b)//build one leaf node
  43. {
  44. root = *TreeArr[a-1];
  45. return;
  46. }
  47. else if(b-a==1)//build 2 leaf node
  48. {
  49. root.left = TreeArr[a-1];
  50. root.right=TreeArr[b-1];
  51. return;
  52. }
  53. //find optimizing point x
  54. int x,minn=INF,curdiff;
  55. for(int i=a;i<b;i++)//find the point that minimize the difference between left and right; this can also be implemented by dichotomy
  56. {
  57. curdiff = Sumvec[i]*2-Sumvec[a-1]-Sumvec[b];
  58. if(abs(curdiff)<minn){
  59. x=i;
  60. minn = abs(curdiff);
  61. }
  62. else break;//because this algorithm has monotonicity
  63. }
  64. HTree*lc = new HTree;   HTree *rc = new HTree;
  65. root.left = lc;     root.right = rc;
  66. Optimize_Tree(a,x,*lc);
  67. Optimize_Tree(x+1,b,*rc);
  68. }
  69. HTree* BuildTree(int* freqency)//create the tree use Optimize_Tree
  70. {
  71. int i;
  72. for(i=0;i<Nsymbols;i++)//statistic
  73. {
  74. if(freqency[i])
  75. TreeArr.push_back(new HTree (NULL,NULL,freqency[i], (char)i));
  76. }
  77. sort(TreeArr.begin(), TreeArr.end(), comp);
  78. memset(Sumvec,0,sizeof(Sumvec));
  79. for(i=1;i<=TreeArr.size();i++)
  80. Sumvec[i] = Sumvec[i-1]+TreeArr[i-1]->weight;
  81. HTree* root = new HTree;
  82. Optimize_Tree(1,TreeArr.size(),*root);
  83. return root;
  84. }
  85. /************************************************************************/
  86. /* Give Shanno Coding to the Shanno Tree
  87. /*PS: actually, this generative process is same as Huffman coding
  88. /************************************************************************/
  89. void Generate_Coding(HTree* root, SF_Code& curcode)
  90. {
  91. if(root->Isleaf())
  92. {
  93. SF_Dic[root->ch] = curcode;
  94. return;
  95. }
  96. SF_Code lcode = curcode;
  97. SF_Code rcode = curcode;
  98. lcode.push_back(false);
  99. rcode.push_back(true);
  100. Generate_Coding(root->left,lcode);
  101. Generate_Coding(root->right,rcode);
  102. }
  103. int main()
  104. {
  105. int freq[Nsymbols] = {0};
  106. char *str = "bbbbbbbccccccaaaaaaaaaaaaaaaeeeeedddddd";//15a,7b,6c,6d,5e
  107. //statistic character frequency
  108. while (*str!='\0')      freq[*str++]++;
  109. //build tree
  110. HTree* r = BuildTree(freq);
  111. SF_Code nullcode;
  112. Generate_Coding(r,nullcode);
  113. for(map<char,SF_Code>::iterator it = SF_Dic.begin(); it != SF_Dic.end(); it++) {
  114. cout<<(*it).first<<'\t';
  115. std::copy(it->second.begin(),it->second.end(),std::ostream_iterator<bool>(cout));
  116. cout<<endl;
  117. }
  118. }

Result:

以上面图中的统计数据为例,进行编码。

符号 A B C D E
计数 15 7 6 6 5

Reference:

  1. Shannon-Fano coding. Wikipedia, the free encyclopedia
  2. Claude Elwood Shannon. Wikipedia, the free encyclopedia.
  3. C. E. Shannon: A Mathematical Theory of Communication. The Bell System Technical Journal, Vol. 27, July, October, 1948.
  4. C. E. Shannon: Prediction and Entropy of Printed English. The Bell System Technical Journal, Vol. 30, 1951.
  5. C. E. Shannon: Communication Theory of Secrecy Systems. The Bell System Technical Journal, Vol. 28, 1949.
  6. http://www.stringology.org/DataCompression/sf/index_en.html

香农-范诺算法(Shannon-Fano coding)原理相关推荐

  1. 香农-范诺编码(Shannon–Fano Coding)

    香农-范诺编码 香农-范诺编码 简介 算法 示例 香农-范诺编码 简介 香农-范诺编码(Shannon–Fano Coding)是一种基于一组符号集及其出现的或然率(估量或测量所得),从而构建前缀码的 ...

  2. java实现.费诺编码_香农费诺编码的matlab实现.doc

    香农费诺编码的matlab实现.doc 信息论与编码实验香农费诺编码的matlab实现学院班级-姓名学号摘要 用预先规定的方法将文字.数字或其他对象编成数码,或将信息.数据转换成规定的电脉冲信号.编码 ...

  3. 香农码字matlab,香农--费诺编码的matlab实现

    香农--费诺编码的matlab实现 信息论与编码实验香农 --费诺编码的 matlab 实现学院:------班级:-----姓名:----学号:----摘要:用 预 先 规 定 的 方 法 将 文 ...

  4. 香农费诺编码 c语言实现,信息论课程设计(香农、费诺编码)

    <信息论课程设计(香农.费诺编码)>由会员分享,可在线阅读,更多相关<信息论课程设计(香农.费诺编码)(34页珍藏版)>请在人人文库网上搜索. 1.华北科技学院信息论基础课程设 ...

  5. 香农费诺编码 c语言实现,对于香农编码、费诺编码和哈夫曼编码,编码方法惟一的是()。...

    问题标题 对于香农编码.费诺编码和哈夫曼编码,编码方法惟一的是(). 2019-8-15来自ip:15.170.14.227的网友咨询 浏览量:533 手机版 问题补充: 题目类型:[填空题] 对于香 ...

  6. labview霍夫曼编码_香农编码与霍夫曼编码

    一.香农-范诺编码 香农-范诺(Shannon-Fano)编码的目的是产生具有最小冗余的码词(code word).其基本思想是产生编码长度可变的码词.码词长度可变指的是,被编码的一些消息的符号可以用 ...

  7. 图像压缩编码——香农/哈夫曼编码

    图像压缩编码--香农/哈夫曼编码 一.信息熵 二.香农-范诺编码 2.1 香农-范诺编码简述 2.2 特例详解 三.哈夫曼编码 3.1 哈夫曼编码简述 3.2 特例详解 四.RGB图像压缩 Endin ...

  8. 克劳德・香农(Claude Shannon)于1937年发表《对继电器和开关电路中的符号分析》

    1911年:6月15日,华尔街金融投资家弗林特(C.Flent)投资霍列瑞斯的制表机公司,成立了全新的CTR公司,但公司创立之初并没有涉足任何电子领域,反而生产诸如碎纸机或者土豆削皮机之类的产品. 1 ...

  9. 香农说,要有熵。信息时代由此开启……

    2016年四月三十日是克劳德·艾尔伍德·香农(Claude Elwood Shannon)的一百周年诞辰.虽然香农被学术届尊为信息时代之父,听说过这位科学巨人名字的想必比知道宋仲基的人少得多.不过不管 ...

  10. 香农编码与Huffman编码之间的对比

    目录 一.[上机目的] 二.[环境] 三.[上机原理] 四.[上机内容] 五.设计思路 5.1霍夫曼编码特点 5.2霍夫曼编码原理 5.3二进制哈夫曼编码过程 5.4计算结果 5.5霍夫曼编码的MAT ...

最新文章

  1. RESTheart官方文档
  2. 如何将一个数组对象 把对象的值用指定符号连接起来 再转为数组 将数组用逗号分隔...
  3. 关于textarea包在div的自适应问题
  4. 记事本 换行符_Windows 记事本再度上架 Microsoft Store
  5. Mapper.xml映射文件---Mybatis学习笔记(八)
  6. 操作 实例 / dom
  7. VSS (Visual Source Safe 2005) 用法详解(转载)
  8. margin系列之负值
  9. hadoop入门学习教程--DKHadoop完整安装步骤
  10. 递归、搜索、贪心、动态规划的区别
  11. c++ 写文件怎么让0x00不被识别成结束符_使用docker-copyedit工具删除镜像中不需要的环境变量和VOLUME...
  12. android: 怎么使用腾讯X5WebView
  13. 学计算机跨考航天航空,北京航空航天大学计算机考研辅导班:跨考考研经验
  14. python如何导入excel表格_使用Python读取电子表格中的数据
  15. CAT的Client端初始化
  16. Ubuntu本地hosts泛解析
  17. 关于LCD_ShowString的顽固感叹号!
  18. 哈勃(Hubble)太空望远镜:人类的大眼睛
  19. unity 入门二 :射击
  20. 【淘宝API开发系列】获得商品评论 API 返回值说明

热门文章

  1. 卡内基梅隆计算机专业,2019美国大学计算机科学专业排名TOP10一览 卡内基梅隆大学居...
  2. ubuntu + gcc-linaro-交叉编译环境搭建
  3. 写剧本、模仿声音、制造笑点,机器学习进军好莱坞
  4. ajax聊天室创建群聊,js+node.js+socket.io实现聊天功能(私聊,创建群聊)
  5. golang的chan有趣用法
  6. 内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)
  7. 易基因|植物育种:ChIP-seq(组蛋白)揭示H3K36me修饰影响温度诱导的植物可变剪接和开花
  8. aho-corasick php,Aho-Corasick自动机浅析
  9. 什么是商业智能(BI)?
  10. Android集成FBReader(精简版)指南