1,霍夫曼编码描述

哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。 在计算机信息处理中,“哈夫曼编码”是一种一致性编码法(又称“熵编码法”),用于数据的无损耗压缩。这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。这种方法是由David.A.Huffman发展起来的。 例如,在英文中,e的出现概率很高,而z的出现概率则最低。当利用哈夫曼编码对一篇英文进行压缩时,e极有可能用一个位(bit)来表示,而z则可能花去25个位(不是26)。用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个位。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。若能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。

2,问题描述

霍夫曼编码前首先要统计每个字的字频,即出现次数,例如:

1、将所有字母出现的次数以从小到大的顺序排序,如上图

2、每个字母都代表一个终端节点(叶节点),比较F.O.R.G.E.T五个字母中每个字母的出现频率,将最小的两个字母频率相加合成一个新的节点。如上图所示,发现F与O的频率最小,故相加2+3=5,将F、O组成一个树,F为左节点,O为右节点,(FO)为根节点,每个节点的取值为其出现频率(FO的出现频率为5)

3、比较5.R.G.E.T,发现R与G的频率最小,故相加4+4=8,将RG组成一个新的节点

4、比较5.8.E.T,发现5与E的频率最小,故相加5+5=10,因此将FO作为左节点,E作为右节点,FOE作为根节点

5、比较8.10.T,发现8与T的频率最小,故相加8+7=15,将RG作为左节点,T作为右节点,RGT作为根节点

6、最后剩10.15,没有可以比较的对象,相加10+15=25,FOE作为左节点,RGT作为右节点

根节点不取值,每个左子节点取值0,右子节点取值1,将每个字母从根节点开始遍历,沿途的取值组成编码:

首先选择一个文本,统计每个字符出现的次数,组成以下数组:

typedef struct FrequencyTreeNode {

int freq;

char c;

struct FrequencyTreeNode *left;

struct FrequencyTreeNode *right;

} FrequencyTreeNodeStruct, *pFrequencyTreeNodeStruct;

然后将获得的数组frequencies进行排序,按照freq由小到大的顺序组成一个二叉查找树,FrequencyTreeNodeStruct,从二叉查找树中找到最小的节点,从树中删除,再取最小的节点,两个子节点,组成一个新的树,根节点c为0,freq为两个子节点的和,加入frequencies中,并排序,重复该步骤,一直到frequencies中只有一个节点,则该节点为Huffman coding tree的根节点

以short类型按照前述的规则为每个字符编码,尔后将文本翻译为Huffman coding,再通过Huffman coding tree进行解码,验证编码的正确性。

3,代码实现

#include

#define n 5 //叶子数目

#define m (2*n-1) //结点总数

#define maxval 10000.0

#define maxsize 100 //哈夫曼编码的最大位数

//定义结构体

typedef struct FrequencyTreeNode {

int freq;

char c;

struct FrequencyTreeNode *left;

struct FrequencyTreeNode *right;

} FrequencyTreeNodeStruct, *pFrequencyTreeNodeStruct;

FrequencyTreeNodeStruct frequencies[MAXALPABETNUM];

typedef struct

{

char bits[n]; //位串

int start; //编码在位串中的起始位置

char ch; //字符

}codetype;

// 读取文件内容,统计字符以及出现频率

void readTxtStatistics(char* fileName)

{

unsigned int nArray[52] = {0};

unsigned int i, j;

char szBuffer[MAXLINE];

int k=0;

// 读取文件内容

FILE* fp = fopen(fileName, \"r\");

if (fp != NULL)

{ /*读取文件内容,先统计字母以及出现次数*/

while(fgets(szBuffer, MAXLINE, fp)!=NULL)

{

for(i = 0; i

{

if(szBuffer[i] <= \'Z\' && szBuffer[i] >= \'A\')

{

j = szBuffer[i] - \'A\';

}

else if(szBuffer[i] <= \'z\' && szBuffer[i] >= \'a\')

{

j = szBuffer[i] - \'a\' + 26;

}

else

continue;

nArray[j]++;

}

}

// 然后赋值给frequencies数组

for(i = 0, j = \'A\'; i

{

if (nArray[i] >0)

{

/*****/

frequencies[k].c=j;

frequencies[k].freq=nArray[i];

frequencies[k].left=NULL;

frequencies[k].right=NULL;

k++;

printf(\"%c:%d\\n\", j, nArray[i]);

}

if(j == \'Z\')

j = \'a\' - 1;

}

}

}

//建立哈夫曼树

void huffMan(frequencies tree[]){

int i,j,p1,p2;//p1,p2分别记住每次合并时权值最小和次小的两个根结点的下标

float small1,small2,f;

char c;

for(i=0;i

{

tree[i].parent=0;

tree[i].lchild=-1;

tree[i].rchild=-1;

tree[i].weight=0.0;

}

printf(\"【依次读入前%d个结点的字符及权值(中间用空格隔开)】\\n\",n);

//读入前n个结点的字符及权值

for(i=0;i

{

printf(\"输入第%d个字符为和权值\",i+1);

scanf(\"%c %f\",&c,&f);

getchar();

tree[i].ch=c;

tree[i].weight=f;

}

//进行n-1次合并,产生n-1个新结点

for(i=n;i

{

p1=0;p2=0;

//maxval是float类型的最大值

small1=maxval;small2=maxval;

//选出两个权值最小的根结点

for(j=0;j

{

if(tree[j].parent==0)

if(tree[j].weight

{

small2=small1; //改变最小权、次小权及对应的位置

small1=tree[j].weight;

p2=p1;

p1=j;

}

else if(tree[j].weight

{

small2=tree[j].weight; //改变次小权及位置

p2=j;

}

tree[p1].parent=i;

tree[p2].parent=i;

tree[i].lchild=p1; //最小权根结点是新结点的左孩子

tree[i].rchild=p2; //次小权根结点是新结点的右孩子

tree[i].weight=tree[p1].weight+tree[p2].weight;

}

}

}

//根据哈夫曼树求出哈夫曼编码,code[]为求出的哈夫曼编码,tree[]为已知的哈夫曼树

void huffmancode(codetype code[],frequencies tree[])

{

int i,c,p;

codetype cd; //缓冲变量

for(i=0;i

{

cd.start=n;

cd.ch=tree[i].ch;

c=i; //从叶结点出发向上回溯

p=tree[i].parent; //tree[p]是tree[i]的双亲

while(p!=0)

{

cd.start--;

if(tree[p].lchild==c)

cd.bits[cd.start]=\'0\'; //tree[i]是左子树,生成代码\'0\'

else

cd.bits[cd.start]=\'1\'; //tree[i]是右子树,生成代码\'1\'

c=p;

p=tree[p].parent;

}

code[i]=cd; //第i+1个字符的编码存入code[i]

}

}

//根据哈夫曼树解码

void decode(hufmtree tree[])

{

int i,j=0;

char b[maxsize];

char endflag=\'2\'; //电文结束标志取2

i=m-1; //从根结点开始往下搜索

printf(\"输入发送的编码(以\'2\'为结束标志):\");

gets(b);

printf(\"编码后的字符为\");

while(b[j]!=\'2\')

{

if(b[j]==\'0\')

i=tree[i].lchild; //走向左子节点

else

i=tree[i].rchild; //走向右子节点

if(tree[i].lchild==-1) //tree[i]是叶结点

{

printf(\"%c\",tree[i].ch);

i=m-1; //回到根结点

}

j++;

}

printf(\"\\n\");

if(tree[i].lchild!=-1&&b[j]!=\'2\') //文本读完,但尚未到叶子结点

printf(\"\\nERROR\\n\"); //输入文本有错

}

void main()

{

printf(\"---------------—— 哈夫曼编码实战 ——\\n\");

printf(\"总共有%d个字符\\n\",n);

frequencies tree[m];

codetype code[n];

int i,j;//循环变量

huffMan(tree);//建立哈夫曼树

huffmancode(code,tree);//根据哈夫曼树求出哈夫曼编码

printf(\"【输出每个字符的哈夫曼编码】\\n\");

for(i=0;i

{

printf(\"%c: \",code[i].ch);

for(j=code[i].start;j

printf(\"%c \",code[i].bits[j]);

printf(\"\\n\");

}

printf(\"【读入内容,并进行编码】\\n\");

// 开始编码

decode(tree);

}

c语言对文本霍夫曼编码,C语言之霍夫曼编码学习相关推荐

  1. c语言如何标志置1与置0,c语言对于文本的基本操作

    字符读写函数  :fgetc和fputc 字符串读写函数:fgets和fputs 数据块读写函数:freed和fwrite 格式化读写函数:fscanf和fprinf 1.字符读写: fgetc函数的 ...

  2. 信息论霍夫曼编码c语言,Huffman 信息论与编码 - 下载 - 搜珍网

    霍夫曼编码/Shiyan4/Shiyan.sln 霍夫曼编码/Shiyan4/Shiyan.suo 霍夫曼编码/Shiyan4/Shiyan.v11.suo 霍夫曼编码/Shiyan4/Shiyan4 ...

  3. 哈夫曼字符串编码c语言实现,基于哈夫曼(haffuman)算法的文件压缩的实现(C语言)(原创)...

    本文首先简要阐述哈夫曼算法的基本思想,然后介绍了使用哈夫曼算法进行文件压缩和解压缩的 处理步骤,最后给出了C语言实现的文件压缩和解压缩的源代码. 哈夫曼算法的主要思想是: ①首先遍历要处理的字符串,得 ...

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

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

  5. 哈夫曼编码c语言实现

    哈夫曼编码的原理看 百度百科 先生成一个哈夫曼树,参考 哈夫曼树c语言实现 生成接近等长码 须要注意的是,为了缩短码长方差,且编出的码更接近于等长码,排序的时候,第一优先级为概率大小,第二优先级为左节 ...

  6. 多媒体技术 || 自适应的霍夫曼编码与原始的霍夫曼编码的比较

    第一题: (a) 自适应的霍夫曼编码与原始的霍夫曼编码相比什么优点: 原始的Huffman算法给出了一种静态的编码树构造方案,要求在实际编码之前统计被编码对象中符号出现的几率,并据此进行编码树的构造. ...

  7. 信息论 输入概率的哈夫曼编码 C语言

    信息论 哈夫曼编码 C语言 哈夫曼编码是一种效率比较高的变长无失真信源编码方法.哈夫曼编码的编码方法,步骤如下: 将信源符号按概率从大到小的顺序排列,为方便起见,令p(a1)>=p(a2)> ...

  8. JPEG编码过程中的霍夫曼编码

    JPEG编码过程中的霍夫曼编码 jpeg文件中的霍夫曼编码分两个部分对DC系数编码和对AC系数的编码. DC系数的编码 编码过程 DC系数的编码由两部分组成, huffman 编码的bitlen + ...

  9. 电文的编码和译码,哈夫曼编码译码(C语言)

    内容: 从键盘接收一串电文字符,输出对应的Huffman(哈夫曼)编码,同时,能翻译由Huffman编码生成的代码串,输出对应的电文字符串.设计要求: (1)构造一棵Huffman树:         ...

  10. 蓝桥哈夫曼树C语言,实验四 哈夫曼树及哈夫曼编码

    实验目的## 掌握哈夫曼树的概念.哈夫曼编码及其应用. 掌握生成哈夫曼树的算法. 会用哈夫曼树对传输报文进行编码. 掌握二叉树的二叉链表存储方式及相应操作的实现. ##实验内容## 用哈夫曼编码进行通 ...

最新文章

  1. 从大型主机到个人计算机:机器人产业可以从pc普及革命中学到什么?
  2. Struts2中的拦截器
  3. Linux下fork()函数
  4. DataSet的数据并发异常处理
  5. 0909关于操作系统
  6. UNIX网络编程 卷2 源代码使用
  7. Android Fragment功能的例子
  8. js的正则表达,只允许数字和特殊
  9. 一文详解 Dubbo 注册发现流程
  10. E/MediaPlayer: Should have subtitle controller already set
  11. IDEA中enter键无法换行
  12. 分享三个可以在家做的正规兼职工作,看到就是赚到
  13. Android NavigationBar 显示 Menu 按键
  14. 商城运费模板数据库简单设计思路
  15. 数据库 - 数据库角色
  16. MarkDown: 为字体添加颜色
  17. 【算法笔记】极客时间 算法面试通关40讲 笔记  覃超
  18. NGINX负载均衡与本地路径映射
  19. Java 从零开始实现微信支付(后台)
  20. iphone5刷机教程

热门文章

  1. 同余方程组,中国剩余定理,孙子定理(学习)
  2. NoClassDefFoundError: ch/qos/logback/classic/spi/ThrowableProxy
  3. 不想被淘汰,大咖有话说——程序猿一定要学大数据?
  4. 一键添加QQ群的方式(更新中。。。)
  5. Python: PS 滤镜--碎片特效
  6. 计算机硬盘根目录是什么,解决方案:硬盘根目录是什么意思?它存储在哪里?...
  7. java加载不了驱动程序,请教java连mysql数据库时一直加载不起驱动
  8. 基于java实现PDF转图片图片合成PDF
  9. 谷粒商城-商城业务-商品详情
  10. WDF队列分析(3)