算法学习-哈夫曼编码(c++实现)
2014-11-27 02:14
483 查看
哈夫曼编码
哈夫曼编码虽然简单,但是是一个非常重要的编码方式,它解决了数据存储的一个非常重要的问题:压缩!它的编码方式是最优的,无损的,尤其在图像中使用的非常多。下面讲下它的原理。
编码方式
哈夫曼编码的构造是依据权值的大小来实现的。首先根据权值构造哈夫曼树,然后对哈夫曼树进行逆向遍历,从而找到每个节点的编码方式。例如:
abbcccdddde这个是一个字符串,一共有5个字符。每个字符的权值就是出现的频率,那么
a就是1,
b权值为2,
c的权值为3,
d的权值为4,
e的权值为1。在普通的编码方式中,表示5个字母最少要3位,也就是3bit.那么这串字符就需要1*3+2*3+3*3+4*3+1*3=33
bits。而使用哈夫曼的编码呢?
构造哈夫曼树的流程是每次找到权值最小的两个,放到一起,组成一颗树,根节点是权值的和。
第一步:
2 / \ 1 1
这样权值为1的
a和
e就已经构造完了。并且把当前的2放回权值列表,下面最小的两个是这个2和
b的权值2。
4 / \ 2 2 / \ 1 1
这样第二步就构造完了,再把4放回权值列表,继续找,依次类推
...省略ing
结果的哈夫曼树:
11 / \ 7 4 / \ / \ 3 4 2 2 / \ 1 1
好,这就是最终的哈夫曼树。看见没有~ 每个叶子节点,都代表了一个字符,1就是
a和
e的。2是
b的,依次...省略ing
然后遍历,左就是
0,右就是
1。
c的就是
00,
d的就是
01,
a的是
100,
b=
11,
e=
101.这样就成功了。
下面验证成果:计算存储空间。从
a到
e:3*1+2*2+2*3+2*4+3*1
= 24 bits。发现没,少了整整9 bits,什么概念?也就是说压缩了接近1/3啊,假如3G大小,压缩后就是2G了啊。
既然这么好,下面附上代码实现。
代码实现
<pre name="code" class="cpp">// // main.cpp // HuffmanCode // // Created by Alps on 14/11/22. // Copyright (c) 2014年 chen. All rights reserved. // #include <iostream> using namespace std; typedef struct HTNode{ int weight; int parent; int lchild; int rchild; HTNode(int w, int p, int l, int r):weight(w),parent(p),lchild(l),rchild(r){} }HTNode, *HuffmanTree; typedef char** HuffmanCode; void Select(HuffmanTree HT, int num, int &child1, int &child2); void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n){ // int m,i; int child1,child2; if (n <= 1) { return; } m = n*2-1;//整棵树的节点数 HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));//申请足够空间 for (i = 1; i <= n; i++,w++) { HT[i] = HTNode(*w, 0, 0, 0); } for (; i <= m; i++) { HT[i] = HTNode(0, 0, 0, 0); } for (i = n+1; i <= m; i++) { Select(HT,i-1,child1,child2); HT[child1].parent = i; HT[child2].parent = i; HT[i].lchild = child1; HT[i].rchild = child2; HT[i].weight = HT[child1].weight + HT[child2].weight; printf("%d==%d\n",child1,child2); } HC = (char**)malloc((n+1)*sizeof(char *)); char *cd = (char*)malloc(n*sizeof(char)); // memset(cd, '\0', n*sizeof(char)); int c = 0; int tempParent,count; for (i = 1; i <= n; i++) { count = 0; for (c = i,tempParent = HT[i].parent; tempParent != 0;c=tempParent, tempParent = HT[tempParent].parent) { if (HT[tempParent].lchild == c) { cd[count++] = '0'; }else{ cd[count++] = '1'; } } cd[count]='\0'; printf("%s~%d\n",cd,i); HC[i] = (char *)malloc((count)*sizeof(char)); for (int j = count; j>=0; j--) { HC[i][count-j] = cd[j-1]; } // strcpy(HC[i], cd); // memset(cd,'\0', n*sizeof(char));//error } } void Select(HuffmanTree HT, int num, int &child1, int &child2){ child1 = 0; child2 = 0; int w1 = 0; int w2 = 0; for (int i = 1; i <= num; i++) { if (HT[i].parent == 0) { if (child1 == 0) { child1 = i; w1 = HT[i].weight; continue; } if (child2 == 0) { child2 = i; w2 = HT[i].weight; continue; } if (w1 > w2 && w1 > HT[i].weight) { w1 = HT[i].weight; child1 = i; continue; } if (w2 > w1 && w2 > HT[i].weight) { w2 = HT[i].weight; child2 = i; continue; } } } } int main(int argc, const char * argv[]) { char a[] = "abcaab"; int i = (int)strlen(a); printf("%d\n",i); int b[]={1,2,3,4}; HuffmanTree HT; HuffmanCode HC; HuffmanCoding(HT, HC, b, 4); for (i = 1; i <= 7; i++) { printf("%d-%d\n",HT[i].weight,HT[i].parent); } for (i = 1; i <=4; i++) { printf("%s\n",HC[i]); } return 0; }
相关文章推荐
- 算法学习-桶排序(Bucket Sort) C++实现
- 算法学习 - 堆排序 ( HeapSort ) C++实现
- 【学习】关于电梯算法的C++实现
- 学习算法 - 表指针实现~ C++
- 机器学习决策树学习算法(C++实现)
- 算法学习 - 括号匹配(栈实现)C++
- 算法学习 - 选择排序的稳定性讨论(C++实现)
- 算法学习 - 快速幂和矩阵快速幂(复杂度Olog(n))C++实现
- 一个无聊男人的疯狂《数据结构与算法分析-C++描述》学习笔记 习题2.8 随机数组的三种生成算法(补) 将bash的实现翻译成比较纯正的bash风格
- 算法学习 - 后缀表达式 (C++ 栈实现)
- 算法学习 - Bellman-Ford(贝尔曼福特)算法(C++实现)
- 算法学习 - 欧几里得算法(辗转相除法)(c++实现)
- 经典算法学习————快速排序算法的c++实现
- 算法学习记录五(C++)--->两个栈实现队列
- 算法学习 - Bloom Filter(布隆过滤器)学习实现(C++实现)
- 算法学习 - Gray Code(格雷码)的解释和c++实现
- 算法学习 - 链表的游标实现~ C++
- 【算法学习】B-Tree编程实现(C++模板类封装)
- 算法学习——搜索和C++ STL 实现全排列和去重全排列
- 一个无聊男人的疯狂《数据结构与算法分析-C++描述》学习笔记 用C++/lua/python/bash的四重实现(7)习题2.8 随机数组的三种生成算法