Huffman 编码原理详解(代码示例)
1、概述
huffman编码是一种可变长编码( VLC:variable length coding))方式,于1952年由huffman提出。依据字符在需要编码文件中出现的概率提供对字符的唯一编码,并且保证了可变编码的平均编码最短,被称为最优二叉树,有时又称为最佳编码。
2、原理
在了解huffman树为最优二叉树时,先要明确下面几个概念:
路径长度:树中一个节点到另一个节点之间分支构成这两个节点之间的路径,路径上的分支数目为其路径长度。
树的路径长度:树根到每一个节点的路径长度之和 为 “l”。
节点的带权路径长度:节点到树根之间的路径长度与节点上权的乘积。
n
树的带权路径长度:所有节点的带权路径长度之和,记作 WPL = ∑wk * lk 。
k=1
n个节点,权值为{ w1, w2, - - -,wn },把此n个节点为叶子节点,构造一个带n个节点叶子节点的二叉树,每个叶子节点的带权路径长度为wi。
取节点a,b,c,d 其w[] = {2, 5, 7, 4},a=7 构造如下三棵树为例:
图1:wpl = 7*2 +5*2 + 2*2 + 4*2 = 36
图2:wpl = 7*3 + 5*3 + 2*1 + 4*2 = 46
图3:wpl = 7*1 + 5*2 + 2*3 + 4*3 = 35
可以证明(图3)其带权路径长度最短,就是huffman树。依次为两节点的连接线编码,左孩子为0,右孩子为1。那么图3就变成了(图33):
编码如下:a(0)、b(10)、c(110)、d(111)
不知道是否有人会问为什么a、b、c、d都是树的叶子节点,而不存在某个是父节点呢?试想,如果a是c、d的父节点,假设a的编码为0,其左右孩子是b、c,那么b,c的编码分别是00,和01,那么当出现诸如010001的压缩串时,可分别解释为caac,cbc,因为在出现a时,如果后面的编码为0,则不确定是解释为aa还是b了,出现歧义就出问题,所以字符只能出现在叶子节点。
在上面我们必须保证须编码的字符必须出现叶子节点,那我们怎么保证(图33)就是最短带权路径呢?我们下面一步步走下去构造huffman树,我们还假设a、b、c、d的带权为7、5、2,4。
3、构造huffman树过程
构造huffman树的哈夫曼算法如下:
(1)n节点的权值{w1、w2、·····,wn}构成n棵二叉树集合F={T1,T2,···,Tn},每棵二叉树Ti只有一个带权为Wi的根节点,左右孩子均空。
(2)在F中选取两棵根节点权值最小的作为树的左右孩子构造一棵新的二叉树,且置根节点的权值为左右孩子权值之和,在F中删除这两棵树,新二叉树之于F中
(3)重复(2),直到F中只有一棵树为止,这棵树就是huffman树。
上面就是以abcd四个节点构造huffman树的过程。
4、代码示例
// Huffman coding.cpp : 定义控制台应用程序的入口点。
//Copyright@Qyee, 2011-7-30#include "stdafx.h"
#include <iostream>
#include <Windows.h>using namespace std;//huffman tree节点定义
typedef struct
{int weight; //保存权值int parent, lchild, rchild; //保存左右孩子的节点值
}HuffmanNode, *HuffmanTree;typedef char **HuffmanCode;void HuffmanCoding(HuffmanTree &HT, int *w, int n); //Huffman编码函数
void select(HuffmanTree HT,int n, int &s1, int &s2);//选择书中节点值较小的两个节点
void Error(char* message); //显示错误信息int w[] = {2, 5, 7, 4}; //各节点权值int main(int argc, char* argv[])
{HuffmanTree HT;HuffmanCoding(HT, w, 6);getchar(); //在win7系统,防止直接跳出,接收字符才执行return语句return 0;
}void HuffmanCoding(HuffmanTree &HT, int *w, int n)
{if (n <= 1)Error("code is small");int m = 2 * n - 1; //n nodes create huffman tree need 2n-1 nodesHT = (HuffmanNode*)malloc((m + 1) * sizeof(HuffmanNode));//Huffman tree的所有节点int s1, s2; //record the two mini weights nodesmemset(HT, 0, (m + 1)* sizeof(HuffmanNode)); //对所有节点初始化为-0//set the n nodesfor (int i = 1; i <= n; i++){HT[i].weight = *w++; //初始化各节点权值}//创建Huffman treefor(int i = n + 1; i <= m; ++i){//选择剩余节点中权值较小的s1和s2select(HT, i - 1, s1, s2);HT[s1].parent = i;HT[s2].parent = i;HT[i].lchild = s1;HT[i].rchild = s2;HT[i].weight = HT[s1].weight + HT[s2].weight;}HuffmanCode HC;int start, c, f;HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));char* cd = (char*)malloc(n * sizeof(char));cd[n - 1] = '\0';for(int i = 1; i <= n; ++i){start = n - 1;for(c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)if (HT[f].lchild == c)cd[--start] = '0';elsecd[--start] = '1';HC[i] = (char*)malloc((n - start) * sizeof(char));strcpy(HC[i], &cd[start]);}for (int i = 1; i <= n; i++){cout<<HC[i]<<endl;}free(cd);free(HC);free(HT);
}void Error(char* message)
{fprintf(stderr, "Error: %s(5s will exit)", message);cout<<"\n";Sleep(5000);exit(1);
}void select(HuffmanTree HT, int n, int &s1, int &s2)
{s1 = 1;s2 = 1;int min = 99999;int i;//选择未被使用的第一个节点,for (i = 1; i <= n; ++i){if (HT[i].parent == 0){min = HT[i].weight;break;}}//find the mini s1for (int p = 1; p <= n; ++p){if(0 == HT[p].parent && min >= HT[p].weight){s1 = p;min = HT[p].weight;}}//find the s2min = 99999;for (int q = 1; q <= n; ++q){if(0 == HT[q].parent && min >= HT[q].weight ){if( q == s1)continue;s2 = q;min = HT[q].weight;}}
}
5、Huffman 编码过程详解
Huffman 编码原理详解(代码示例)相关推荐
- Huffman编码原理详解
转载自这里 1.概述 huffman编码是一种可变长编码( VLC:variable length coding))方式,于1952年由huffman提出.依据字符在需要编码文件中出现的概 ...
- 『ML笔记』HOG特征提取原理详解+代码
HOG特征提取原理详解+代码! 文章目录 一. HOG特征介绍 二. HOG算法具体流程+代码 2.1. 图像灰度化和gamma矫正 2.2. 计算图像像素梯度图 2.3. 在8×8的网格中计算梯度直 ...
- urlencode 与urldecode 函数字符编码原理详解
中文字符编码研究系列第五期,详解 urlencode()与urldecode()函数字符编码原理,两个函数分别用于编码 URL 字符串和解码已编码的 URL 字符串,实现对中文字符的编码 <if ...
- python压缩算法_LZ77压缩算法编码原理详解(结合图片和简单代码)
前言 LZ77算法是无损压缩算法,由以色列人Abraham Lempel发表于1977年.LZ77是典型的基于字典的压缩算法,现在很多压缩技术都是基于LZ77.鉴于其在数据压缩领域的地位,本文将结合图 ...
- 8B/10B编码原理详解、Verilog实现及在JESD204B中的应用
目录 1.8B/10B介绍 2.原理 3.Verilog实现 4.实例:在JESD204B中的应用 参考资料: 1.8B/10B介绍 8B/10B编码的目的是防止串行的数据出现长时间的连0连1,因为这 ...
- 编码原理详解(五)---熵编码(CAVAL)
上一篇我们讲到了ZigZag扫描,经过这一扫描之后,发现原本是4*4的像素矩阵,就变成了一连串的数字,可以说是二维到一维的一个转换吧,而且经过ZigZag扫描后,一连串的数字的最后大部分为0,以及一些 ...
- 加密系列 | 3DES加密和解密算法详解代码示例
3DES的在Java的实现与DES类似,如下代码为3DES加密算法.CBC模式.PKCS5Padding填充方式的加密解密结果,参考代码如下所示: import java.security.Key;i ...
- 王学岗——H265编码原理详解与码流分析(对应第五节课)
H264在分辨率高的情况下缺点 1,94年h264开始研制. 2,现在屏幕变的越来越大.假设h264以16X16进行编码,但我们的屏幕宽达到了32000像素.编码一帧画面需要400000个宏块.94年 ...
- python 编码解码原理_Python JSON编解码方式原理详解
这篇文章主要介绍了Python JSON编解码方式原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 概念 JSON(JavaScript Ob ...
最新文章
- 2022秋招大战:算法岗挤破头,JAVA开发也被迫内卷
- Oracle 存储过程异常处理
- 利用circpedia 数据库探究circRNA的可变剪切
- SAP后台作业记录操作
- 预训练模型真的越大越好吗?听听他们怎么说
- QtCreator添加图片资源
- 霍金首次公开24岁时博士论文 把剑桥的服务器搞瘫痪了……
- 选项类 oracle ebs,Oracle EBS 打3类补丁主要步骤
- Linux yum 安装
- mysql decimal 上限_关于mysql的decimal类型的外键的一个特殊限制
- Arrays.asList 方法注意事项
- proguard 反编译_Android Studio项目结构,编译器,ProGuard
- PyCharm 2020.2.3复制粘贴及删除键修正
- 的正确使用_如何正确使用隔离霜
- 给Ionic写一个cordova(PhoneGap)插件
- 通过下面语句创建employee数据库和dept(部门表)、emp(员工表)、salgrade(工资等级表)34题
- Parallels Desktop 17.x by TNT 出现网络初始化失败怎么办
- Java并发基础知识(五)
- 交换机ARP代理详解
- 38年后的今天,用数据回顾什么是女排精神?