Huffman 编码树

Huffman 编码树Huffman 编码树像 SCAII 这样即那个每个字符表示为一个 7 为二进制的序列的编码方式称为定长编码 它们采用同样数目的二进制位表示消息中的一个字符 与之相对应的是变长编码 即用可变的二进制位数表示不同的字符 一般而言 如果在我们的消息中 某写符号出现得比较频繁 而另一些比较少见 那么就可以通过为这些出现比较频繁的字符指定比较短的二进制位编码来达到节省空间的目的 但是采用二

Huffman 编码树

像SCAII这样即那个每个字符表示为一个7为二进制的序列的编码方式称为定长编码,它们采用同样数目的二进制位表示消息中的一个字符.与之相对应的是变长编码,即用可变的二进制位数表示不同的字符.

一般而言,如果在我们的消息中,某写符号出现得比较频繁,而另一些比较少见,那么就可以通过为这些出现比较频繁的字符指定比较短的二进制位编码来达到节省空间的目的.

但是采用二进制编码有一个困难,它需要在读二进制序列是判断合适到达了一个字符的结束.解决这一问题的方法可以在每个字母后面用一个特殊分隔符(莫尔编码). 另一种解决方式是设计编码方式,是得其中每个字符的完整编码都不是另一个字符编码的开始一段.这中编码方式称为前缀编码.一般而言能够通过变长前缀码去利用编码消息中符号出现的相对频度,就能节省空间.完成这一特定时间的方式称为Huffman编码.一个Huffman编码可以表示为一个二叉树,其中的树叶是被编码的符号.树中的每个每个非叶子节点代表一个集合,其中包含饿这一节点之下的所有书上的符号.每个位于书上的符号被赋予一个权重,也就是它的相对频度.非叶子节点所包含的权重位是位于它之下的所有叶子节点的权重之和.这种权重在编码和解码中国并不使用.

下图是一颗Huffman编码树

Huffman 编码树



在用Huffman树做一个序列解码时,我们从树根开始,通过位序列中的0或者1确定是向左移动还是向右移动.每当达到一个叶子节点时就生成出一个符号,然后再从新从树根开始去确定下一个符号,直到解码完给定的的二进制序列为止.

列如,如果有一个序列 .从数根开始,序列的第一位是1, 所以我们向右分支移动,第二位是0,所以我们向左移动,第三位是0 ,所以向左移动.这是已经到达Bde叶,所以被解码消息中的第一个符号是B.接着再从树根开始重复上述过程,最后可以确定整个消息是BAC.



生成Huffman树

给定了符号的 符号表和它们的相对频度,怎么才能构造出最好的编码?(也就是怎样的树能是消息编码的位数最少).Huffman给出了完成这一事件的一个算法,并且证明给了对于符号所出现的相对频度与构造树的消息符号的消息而言,这样产生的编码是最好的边长编码.

生成Huffman树的算法非常简单,就是安排这棵树,使得那些带有最低平度的符号出现在离树根最远的地方.这一构造过程从叶节点的集合开始,这种节点中包含包含各个符号和他们出现的频度,这就是开始构造编码数的初始数据.现在要找出连个具有最低权重的叶,并归并它们,产生出一个以这两个节点为左右分支的节点.新节点的权重就是这两个叶节点的权重之和.然后继续重复这一过程当集合只剩下一个节点时停止,而这个节点就是根节点.



Huffman 编码树

这一算法不总能描述一棵唯一的树,这是因为每步选择出的最小权重节点可能不唯一,在左归并是,两个节点的顺序也是任意的,也就是说,随便哪个都可以作为左分支,或者右分支.

=====================================================

代码来自维基百科

//以下為C++程式碼,在GCC下編譯通過 //僅用於示範如何根據權值構建霍夫曼樹, //沒有經過性能上的優化及加上完善的異常處理。 #include <cstdlib> #include <iostream> #include <deque> #include <algorithm> using namespace std; const int size=10; struct node //霍夫曼樹節點結構 { unsigned key; //保存權值 node* lchild; //左孩子指針 node* rchild; //右孩子指針 }; deque<node*> forest; deque<bool> code; //此處也可使用bitset node* ptr; int frequency[size]={0}; void printCode(deque<bool> ptr); //用於輸出霍夫曼編碼 bool compare( node* a, node* b) { return a->key < b->key; } int main(int argc, char *argv[]) { for(int i=0;i<size;i++) { cin>>frequency[i]; //輸入10個權值 ptr=new node; ptr->key=frequency[i]; ptr->lchild=NULL; ptr->rchild=NULL; forest.push_back(ptr); }//形成森林,森林中的每一棵樹都是一個節點 //從森林構建霍夫曼樹 for(int i=0;i<size-1;i++) { sort(forest.begin(),forest.end(),compare); ptr=new node; //以下代碼使用下標索引隊列元素,具有潛在危險,使用時請注意 ptr->key=forest[0]->key+forest[1]->key; ptr->lchild=forest[0]; ptr->rchild=forest[1]; forest.pop_front(); forest.pop_front(); forest.push_back(ptr); } ptr=forest.front();//ptr是一個指向根的指針 system("PAUSE"); return EXIT_SUCCESS; } void printCode(deque<bool> ptr) { //deque<bool> for (int i=0;i<ptr.size();i++) { if(ptr[i]) cout<<"1"; else cout<<"0"; } }





维基百科连接:http://zh.wikipedia.org/wiki/霍夫曼编码



版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232687.html原文链接:https://javaforall.net

(0)
上一篇 2025年9月22日 上午9:01
下一篇 2025年9月22日 上午9:22


相关推荐

  • java-xml文件

    java-xml文件使用DOM思想,读取xml文件介绍dom4j核心类1。SAXReaderDOM解析思想的核心类方法:read(绑定了这个xml文件的输入流)读取xml文件返回文档对象,返回值是Doucment对象2.Doucment对象方法:getRootElement()获取文档的根标签返回值:返回的是标签对象Element3.Element标签对象方法获取子标签Listelements()返回所有子标签集合List方法:StringattributeValues(String属性

    2022年7月8日
    21
  • java 调用asmx[通俗易懂]

    java 调用asmx[通俗易懂]packagecom.webservice.test;importjava.util.Vector;importjavax.xml.namespace.QName;importjavax.xml.rpc.ParameterMode;importjavax.xml.rpc.encoding.XMLType;importorg.apache.axis.clien

    2022年6月9日
    42
  • Unity与 SO 交互 ☀️| 详细讲解 怎样通过 Android Studio 生成一个.so文件 并简单调用!

    Unity与 SO 交互 ☀️| 详细讲解 怎样通过 Android Studio 生成一个.so文件 并简单调用!本文章是Unity与SO交互的内容,详细的将每一步都做了介绍,生成一个so文件其实很简单!该专栏还有多篇优质内容在等待你观看。

    2022年7月21日
    19
  • minio节点扩展_多节点部署定时任务

    minio节点扩展_多节点部署定时任务1.概述分布式Minio可以让你将多块硬盘(甚至在不同的机器上)组成一个对象存储服务。由于硬盘分布在不同的节点上,分布式Minio避免了单点故障。在大数据领域,通常的设计理念都是无中心和分布式。Minio分布式模式可以帮助你搭建一个高可用的对象存储服务,你可以使用这些存储设备,而不用考虑其真实物理位置。数据保护分布式Minio采用纠删码来防范多个节点宕机和位衰减bitrot。分布式Minio至少需要4个硬盘,使用分布式Minio自动引入了纠删码功能。高可用单机Mi..

    2022年10月8日
    5
  • 数组求和方法汇总_用函数的方法对输入的数组求和

    数组求和方法汇总_用函数的方法对输入的数组求和vararr=[1,2,3,4,5,6];测试时我不想过度使用全局变量影响命名空间,所以没使用未声明变量。而是直接通过私有作用域设置静态私有变量,也可以用其他设计模式来限定变量作用域。因为数组对象的迭代方法也是一种遍历,所以也可以借助用来实现求和。一、利用数组对象的各迭代方法:1.array.every()查询是否有所有项都匹配的方法:1(function(){…

    2026年4月17日
    5
  • mariadb 的安装及基本配置

    mariadb 的安装及基本配置文章目录一、mariadb介绍二、mariadb下载及安装三、mariadb的启停命令四、mariadb的配置五、添加用户,设置权限Navicat连接数据库一、mariadb介绍MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可。开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将MySQL闭源的潜在风险,因此社区采用分支的方式来避开这个风险。MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎

    2022年5月16日
    68

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号