哈夫曼树以及哈夫曼编码
来源:互联网 发布:php 修改$_get 编辑:程序博客网 时间:2024/05/13 08:52
哈夫曼树又叫最优二叉树,即叶子结点带权路径长度之和(WPL)最小。
关于哈夫曼树有在以下链接中的作者解释的很详细,不太清楚的同学可以去看一下。
https://www.cnblogs.com/zhangming-blog/p/5395950.html
下面我想补充下下哈夫曼编码,哈夫曼编码又称霍夫曼编码,或者最优编码。哈夫曼编码主要有以下特点:
一 : 不等长编码;
二: 最优编码;
三: 无歧义编码,即任意字符的编码都不是另一字符的前缀;
四: 所有应编码的字符位于叶子结点。
哈夫曼编码采用的是二进制编码方式,父结点与左儿子结点之间的路径编为0,与右儿子结点之间的路径编为一。举个例子来说明一下。
在这个例子中,1,2,3,4为待编码的字符.
1的编码序列为: 110
2的编码序列为: 111
3的编码序列为: 10
4的编码序列为: 0
可以看出,各字符的编码序列不尽相同,权重越大编码序列越短,即路径越短。
WPL = 1*3 + 2*3 + 3*2 + 4*1 = 19
需要注意的是:哈夫曼树一定是最优编码,但最优编码不一定需要通过哈夫曼树实现。这一点哈夫曼先生在他的论文也有说明,有兴趣的同学可以验证下。
下面是哈夫曼树的结构:
struct Node{ int weight; //权重 int *code; //编码 int codeLen; //编码长度 Huffman left; //左孩子结点 Huffman right; //右孩子结点};
以下哈夫曼树的创建代码:
Huffman Creat_Huffman(int N){ int i, n; MinHeap H; Huffman T; H = Creat_MinHeap(N); //创建最小堆 n = H->size; for( i = 1; i < n; i++ ) { T = (Huffman)malloc( sizeof( struct Node ) ); //创建一个根结点 T->left = Delete(H); //从最小堆中取权重最小的结点赋给左孩子结点 T->right = Delete(H); //同上 T->weight = T->left->weight + T->right->weight; //父节点的权重等于左右孩子结点权重之和 Insert( H, T ); //将父节点放入最小堆中 } T = Delete(H); // T指向堆中的头结点也就是哈夫曼树的根结点 return T;}
上面的代码中哈夫曼树的创建借助了最小堆来实现,对最小堆不太清楚的同学可以去看我的另一篇关于最小堆的博客。
此为链接:最小堆
下面是哈夫曼编码的代码实现:
void HuffmanCode( Huffman T, int len ){ static int s[20]; //静态数组,存储数据编码 if( T ) { if( !T->left && !T->right ) { printf("结点权重为 %-3d 的编码是: ", T->weight); T->code = (int *)malloc( len * sizeof( int ) ); //开辟空间存储叶子结点编码 for( int i = 0; i < len; i++) { T->code[i] = s[i]; //将字符的编码存入对应结点中 printf("%d", T->code[i]); } T->codeLen = len; //存储编码长度 printf("\n"); } else { //递归遍历各结点的路径 s[len] = 0; HuffmanCode( T->left, len+1 ); s[len] = 1; HuffmanCode( T->right, len+1 ); } }}
以下为全代码实现:
#include<stdio.h>#include<malloc.h>#define ElementType Huffman#define MaxSize 100 //堆堆的最大空间typedef struct Node* Huffman;typedef struct Heap* MinHeap;struct Node{ int weight; //权重 int *code; //编码 int codeLen; //编码长度 Huffman left; //左孩子结点 Huffman right; //右孩子结点};struct Heap{ ElementType *element; //存储元素 int size; //元素的数量 int capacity; //堆的最大空间};//插入一个元素void Insert(MinHeap H, Huffman e){ int i; if( H->size == H->capacity ) //判断堆是否已满 { printf("堆已满!"); return ; } i = ++H->size; //所存元素数量加1 for( ; i>=2 && H->element[i/2]->weight > e->weight; i /= 2) //当要插入的元素小于父节点时,父节点向下挪动,要插入的元素继续向上比较 H->element[i] = H->element[i/2]; H->element[i] = e;}//创建最小堆MinHeap Creat_MinHeap(int n){ ElementType tmp; int i; MinHeap H = (MinHeap)malloc( sizeof(struct Heap) ); H->element = (ElementType*)malloc( (MaxSize+1) * sizeof(ElementType) ); H->size = 0; H->capacity = MaxSize; for( i = 1; i <= n; i++ ) //将元素按输入顺序放入数组中 { tmp = (ElementType)malloc( sizeof( struct Node ) ); tmp->left = NULL; tmp->right = NULL; scanf("%d", &tmp->weight); Insert( H, tmp ); } return H;}//删除根结点并返回其值ElementType Delete(MinHeap H){ int parent, child; ElementType tmp, e; if( H->size == 0) { printf("堆为空!"); return 0; } e = H->element[1]; tmp = H->element[H->size--]; for( parent = 1; parent*2 <= H->size; parent = child ) { child = parent * 2; if(child != H->size && H->element[child+1]->weight < H->element[child]->weight) child++; //child指向左右儿子中较小的那个; if( tmp->weight <= H->element[child]->weight ) //如果tmp小于等于左右儿子中较小的那个,结束循环 break; else //否则,较小的儿子上移,tmp进入下一层 H->element[parent] = H->element[child]; } H->element[parent] = tmp; return e;}//先序遍历输出哈夫曼树void Print( Huffman T ){ if( T ) { printf("%d ", T->weight); Print( T->left ); Print( T->right ); }}Huffman Creat_Huffman(int N){ int i, n; MinHeap H; Huffman T; H = Creat_MinHeap(N); //创建最小堆 n = H->size; for( i = 1; i < n; i++ ) { T = (Huffman)malloc( sizeof( struct Node ) ); T->left = Delete(H); T->right = Delete(H); T->weight = T->left->weight + T->right->weight; Insert( H, T ); } T = Delete(H); return T;}//哈夫曼编码void HuffmanCode( Huffman T, int len ){ static int s[20]; //静态数组,存储数据编码 if( T ) { if( !T->left && !T->right ) { printf("结点权重为 %-3d 的编码是: ", T->weight); T->code = (int *)malloc( len * sizeof( int ) ); //开辟空间存储叶子结点编码 for( int i = 0; i < len; i++) { T->code[i] = s[i]; //将字符的编码存入对应结点中 printf("%d", T->code[i]); } T->codeLen = len; //存储编码长度 printf("\n"); } else { //递归遍历各结点的路径 s[len] = 0; HuffmanCode( T->left, len+1 ); s[len] = 1; HuffmanCode( T->right, len+1 ); } }}//计算带权最优编码长度int WPL( Huffman T ){ if( !T->right && !T->left) { return T->weight*T->codeLen; } else return ( WPL( T->left ) + WPL( T->right ) );}int main(){ int N; Huffman T; scanf("%d", &N); //需要编码的字符数量 T = Creat_Huffman(N); //创建哈夫曼树 printf("\n哈夫曼树先序遍历结果为: "); Print( T ); //先序遍历哈夫曼树 printf("\n"); HuffmanCode( T, 0 ); //对字符进行编码 printf("最优编码长度为: %d\n", WPL( T )); //输出带权路径之和 return 0;}
以上即为所有代码,不懂之处,欢迎交流,不足之处,恳请指正。
阅读全文
0 0
- 哈夫曼树以及哈夫曼编码
- 哈夫曼树以及哈夫曼编码 .
- 哈夫曼树以及哈夫曼编码
- 哈夫曼树以及哈夫曼编码
- 哈夫曼树以及哈夫曼编码
- 哈夫曼树以及哈夫曼编码的实现
- 哈夫曼树以及哈夫曼编码的创建
- 哈夫曼树的建立以及哈夫曼编码
- c++哈夫曼树以及编码
- 哈夫曼树以及编码
- 哈夫曼编码原理以及实现
- 哈夫曼树的构造以及编码
- 哈夫曼树的创建以及编码
- 数据结构(15)--哈夫曼树以及哈夫曼编码的实现
- 哈夫曼树的构建以及哈夫曼编码的输出
- 【哈夫曼树】哈夫曼树的实现以及哈弗曼编码
- 哈夫曼树的构造以及编码实现
- 设计、编码以及其他
- VS2012创建ATL工程及使用MFC测试COM组件
- 汇总-oc
- 使用Quartz进行作业任务调度
- 如何解决段错误
- 9.输出10个斐波那契(Fibonacci)数列:1 1 2 3 5 8 13 21 34 55
- 哈夫曼树以及哈夫曼编码
- SpringMVC知识点总结(1)
- Python分析网易云音乐近5年热门歌单
- logsit回归代码的推导
- HDU 1010 Tempter of the Bone(DFS+奇偶剪枝)
- 演讲
- jquery html-与-text方法的区别
- 简析C++模板
- map-reduce Java API操作及map reduce的配置