算法导论之哈夫曼编码
来源:互联网 发布:php 日期格式转换 编辑:程序博客网 时间:2024/05/25 05:37
今天和大家一起讨论Haffman编码,哈夫曼编码是基于哈夫曼树,也可以被称为最有二叉树,哈夫曼编码可以有效的压缩数据,通常可以节省20%~90%,具体的压缩率依赖于数据的特性。首先给大家介绍一下什么是最优二叉树;在介绍什么是最有二叉树之前,先说明两个概念 ,
i>叶子节点的路径长度:从根到叶子节点的边的个数;
ii>叶子节点的带权路径长度(WPL):叶子节点的权值 * 路径长度;
(1) 最优二叉树(Haffman Tree):一颗二叉树的所有叶子节点的带权路径长度之和最小。
例:有节点 A(9)、B(2)、C(7)、D(4)
第一种构建二叉树的方式:
X
/ \
X X
/ \ / \
A B C D
其WPL值为:(9 + 2+ 7 + 4)* 2 = 44
第二种构建二叉树的方式:
X
/ \
A X
/ \
C X
/ \
B D
将权值大放在靠近根结点的位置;其WPL值为:9 + 7 * 2 + (2 + 4)*3 = 41
(2)构造哈夫曼树 ------->贪心算法
i> 初始 :森林:F = {A(9)、B(2)、C(7)、D(4)}
ii>处理:从森林中选取权值最小和次小的2颗树构建成一颗新二叉树,并放回森林,并删除原来的2颗二叉树
iii>重复ii>,直至森林中只剩一颗二叉树。
例:F = {A、B、C、D}
i> 6
/ \
B D ---> 放回森林,并删除B、D两颗二叉树
(2) (4)
ii> 13
/ \
6 C(7) --->放回森林,并删除6、C两颗二叉树
/ \
B D
(2) (4)
iii> 22
/ \
A 13
(9) / \
6 C(7)
/ \
B D
(2) (4)
在构造二叉树时会遇到以下的几个问题:
A>如何查找权值最小和次小的两颗子树:-------贪心准则
B>如何构建一颗新的子树:
i>创建双亲 ----权值为左右子树之和
ii>左子女 --->最小 右子女 --->次小
C>如何知道森林中只剩下一颗子树 -------->结束条件
i>Haffman树无单分支节点
ii>经过n - 1次就可构建完成
实现Haffman Tree
1)存储结构:
word weight left right parent code
A 9 -1 -1 -1
B 2 -1 -1 -1
C 7 -1 -1 -1
D 4 -1 -1 -1
定义存储结构:
下面实现接口:
#include <stdio.h>#include <stdlib.h>#include "hafman.h"#include "tools.h"HaffTree *init(char * s,int * a,int n){ HaffTree *F = {0}; int i = 0; F = (HaffTree *)Malloc(((2 * n) - 1) * sizeof(HaffTree)); for(i = 0;i < n;i++){ F[i].word = s[i]; F[i].weight = a[i]; F[i].left = -1; F[i].right = -1; F[i].parent = -1; } return F;}void Creat_HaffmanTree(HaffTree *F,int n){ int i = 0; int k1 = 0; int k2 = 0; int j = 0; for(i = 0;i < n -1 ; ++i){ for(k1 = 0;k1 < n + i && F[k1].parent != -1;k1++); for(k2 = k1 + 1;k2 < n + i && F[k2].parent != -1;k2++); for(j = k2;j < n + i;j++){ if(F[j].parent == -1){ if(F[j].weight < F[k1].weight){ k2 = k1; k1 = j; }else if(F[j].weight < F[k2].weight){ k2 = j; } } } F[n + i].word = 'x'; F[n + i].weight = F[k1].weight + F[k2].weight; F[n + i].left = k1; F[n + i].right = k2; F[n + i].parent = -1; F[k1].parent = n + i; F[k2].parent = n + i; }}void Haffman_Code(HaffTree *F,int n){ int i = 0; int c = 0; int p = 0; int k = 0; for(i = 0;i < n;++i){ F[i].code = (int *)Malloc((n + 1) * sizeof(int)); F[i].code[0] = 0; c = i; while(F[c].parent != -1){ p = F[c].parent; k = ++F[i].code[0]; if(F[p].left == c){ F[i].code[k] = 0; }else{ F[i].code[k] = 1; } c = p; } }}void Print_Haffmancode(HaffTree *F,int n){ int i = 0; int j = 0; for(i = 0;i < n;++i){ printf("%c:",F[i].word); for(j = F[i].code[0];j > 0;--j){ printf("%2d",F[i].code[j]); } printf("\n"); }}void ClearHaffman(HaffTree *F,int n){ int i = 0; for(i = 0;i < n;++i){ free(F[i].code); } free(F);}测试代码:
测试结果:
从程序执行结果上可看出实现了压缩数据,节省了空间。
- 算法导论之哈夫曼编码
- 算法导论之贪心算法:哈夫曼编码
- 算法导论 哈夫曼编码
- 算法导论哈夫曼编码
- 算法导论之--------------Huffman编码
- 【算法导论】贪心算法之赫夫曼编码
- 算法导论之贪心算法(Huffman编码和拟阵)
- 基于visual Studio2013解决算法导论之047赫夫曼编码
- [算法导论读书笔记]huffman编码
- 算法导论之九链表
- 算法导论之堆
- 算法导论之基础知识
- 算法导论之红黑树
- 排序算法之导论
- 算法导论之二叉排序树
- 算法导论之红黑树
- 算法导论之数据结构
- 算法导论之二项堆
- sip注册流程
- 自定义ViewGroup---理解1
- Android EditText的完全解析(随时补充)
- 尴尬的VXLAN
- QT TTS朗读
- 算法导论之哈夫曼编码
- Spring > 统一异常处理
- ORA-01097错误解决办法及探索shutdown immediate
- 计算日期或时间间隔解决办法
- Android开发学习总结(一)——搭建最新版本的Android开发环境
- C-1-数据类型-p5
- rlwrap安装Invalid configuration `x86_64-unknown-linux-':问题解决
- AngularJS的路由、模块、依赖注入
- mysql-触发器