基于二叉树和数组实现限制长度的最优Huffman编码
具体介绍详见上篇博客:基于二叉树和双向链表实现限制长度的最优Huffman编码
基于数组和基于链表的实现方式在效率上有明显区别:
编码256个符号,符号权重为1...256,限制长度为16,循环编码1w次,Release模式下。基于链表的耗时为8972ms,基于数组的耗时为1793ms,速度是链表实现方式的5倍.
详细代码例如以下:
- //Reference:A fast algorithm for optimal length-limited Huffman codes.pdf,http://pan.baidu.com/s/1o6E19Bs
- //author:by Pan Yumin.2014-06-18
- //with the method of BinaryTree and linked-list
- #include <stdio.h>
- #include <memory.h>
- #include <malloc.h>
- #define MaxSymbols 256 //the Maximum Number of Symbols
- #define MaxHuffLen 16 //the Limited Length
- typedef unsigned char boolean;
- #ifndef FALSE //in case these macros already exist
- #define FALSE 0 //values of boolean
- #endif
- #ifndef TRUE
- #define TRUE 1
- #endif
- typedef struct __Node{
- int width;
- int weight;
- int index;
- int depth;
- struct __Node *left; //left child
- struct __Node *right; //right child
- }Node;
- typedef struct __HuffTable{
- unsigned int index;
- unsigned int len;
- unsigned int code;
- }HuffTable;
- //Test memory leak
- /*int g_malloc = 0,g_free = 0;
- void* my_malloc(int size){
- g_malloc++;
- return malloc(size);
- }
- void my_free(void *ptr){
- if(ptr){
- g_free++;
- free(ptr);
- ptr = NULL;
- }
- }
- #define malloc my_malloc
- #define free my_free*/
- //Get the smallest term in the diadic expansion of X
- int GetSmallestTerm(int X)
- {
- int N=0;
- while((X & 0x01) == 0){
- X >>= 1;
- N++;
- }
- return 1<<N;
- }
- void RemoveNodeMark(Node *tree,unsigned char *Flag,int Symbols)
- {
- if(tree->left == NULL && tree->right == NULL){
- Flag[tree->depth*Symbols+tree->index] = 0; //set the nodemark zero
- }
- if(tree->left){
- RemoveNodeMark(tree->left,Flag,Symbols);
- }
- if(tree->right){
- RemoveNodeMark(tree->right,Flag,Symbols);
- }
- }
- void PrintHuffCode(HuffTable Huffcode)
- {
- int i;
- for(i=Huffcode.len-1;i>=0;i--){
- printf("%d",(Huffcode.code>>i) & 0x01);
- }
- }
- void GenerateHuffmanCode(HuffTable *HuffCode,unsigned char *Flag,int L,int Symbols,int *SortIndex)
- {
- char Code[17];
- int Pre_L = 0;
- int i=0,j=0;
- unsigned int codes[MaxHuffLen+2]={0},rank[MaxHuffLen+1] = {0}; //rank: the number of symbols in every length
- //find the first code
- for(i=0;i<Symbols;i++){
- for(j=0;j<L;j++){
- HuffCode[i].len += Flag[j*Symbols+i];
- }
- if(HuffCode[i].len != 0)
- rank[HuffCode[i].len]++;
- HuffCode[i].index = SortIndex[i];
- }
- for(i=0;i<=L;i++){
- codes[i+1] = (codes[i]+rank[i])<<1;
- rank[i] = 0;
- }
- //code
- for(i=0;i<Symbols;i++){
- HuffCode[i].code = codes[HuffCode[i].len] + rank[HuffCode[i].len]++;
- }
- }
- float BitsPerSymbol(HuffTable *HuffCode,int *weight,int Symbols,int WeightSum)
- {
- float bitspersymbol = 0.0;
- int i;
- for(i=0;i<Symbols;i++){
- bitspersymbol += (float)HuffCode[i].len*weight[i];
- }
- return bitspersymbol/WeightSum;
- }
- //ascending order
- void FreqSort(int *Freq,int *SortIndex,int Symbols)
- {
- int i,j,tmp;
- for(i=0;i<Symbols;i++){
- for(j=i+1;j<Symbols;j++){
- if(Freq[i]>Freq[j]){
- tmp = Freq[i];
- Freq[i] = Freq[j];
- Freq[j] = tmp;
- tmp = SortIndex[i];
- SortIndex[i] = SortIndex[j];
- SortIndex[j] = tmp;
- }
- }
- }
- }
- //ascending order, quick sort
- void QuickSort(int *arr, int *SortIndex,int startPos,int endPos)
- {
- int i,j,key,index;
- key=arr[startPos];
- index = SortIndex[startPos];
- i = startPos; j = endPos;
- while(i < j){
- while(arr[j]>=key && i<j)
- --j;
- arr[i]=arr[j]; SortIndex[i] = SortIndex[j];
- while(arr[i]<=key && i<j)
- ++i;
- arr[j]=arr[i]; SortIndex[j] = SortIndex[i];
- }
- arr[i]=key; SortIndex[i] = index;
- if(i-1 > startPos)
- QuickSort(arr,SortIndex,startPos,i-1);
- if(endPos > i+1)
- QuickSort(arr,SortIndex,i+1,endPos);
- }
- int GenLenLimitedOptHuffCode(int *Freq,int Symbols)
- {
- int i,j;
- unsigned char *Flag = NULL; //record the state of the node
- unsigned int rank[MaxHuffLen];
- Node *tree = NULL, *base = NULL, *left = NULL, *right = NULL;
- Node *start = NULL, *end = NULL, *Last = NULL; //start:the first(min weight) node of 2*r,end:the last(max weight) node of 2*r,Last:the last node of array.
- Node *node = NULL;
- HuffTable HuffCode[MaxSymbols];
- float bitspersymbols = 0.0;
- int WeightSum = 0;
- int SortIndex[MaxSymbols];
- int X = (Symbols-1)<<MaxHuffLen; //avoid float calculation
- int minwidth,r,weight;
- int r_Num = 0;
- if(Symbols > (1<<MaxHuffLen)){
- printf("Symbols > (1<<MaxHuffLen)\n");
- return -1;
- }
- for(i=0;i<MaxSymbols;i++){
- SortIndex[i] = i;
- }
- //FreqSort(Freq,SortIndex,Symbols); //sort
- QuickSort(Freq,SortIndex,0,Symbols-1); //sort
- for(i=0;i<Symbols;i++){
- WeightSum += Freq[i];
- }
- tree = (Node *)malloc(Symbols*MaxHuffLen*2*sizeof(Node));
- memset(tree,0,Symbols*MaxHuffLen*2*sizeof(Node)); //2: for the optimize
- Flag = (unsigned char*)malloc(MaxHuffLen*Symbols*sizeof(unsigned char));
- memset(Flag,0x01,MaxHuffLen*Symbols*sizeof(unsigned char)); //mark every node 1
- memset(HuffCode,0,sizeof(HuffCode));
- for(i=0;i<MaxHuffLen;i++){
- for(j=0;j<Symbols;j++){
- tree[i*Symbols+j].depth = i;
- tree[i*Symbols+j].index = j;
- tree[i*Symbols+j].width = 1<<i; //avoid float calculation
- tree[i*Symbols+j].weight = Freq[j];
- }
- }
- //start code
- base = tree; Last = tree+MaxHuffLen*Symbols-1;
- while(X>0){
- minwidth = GetSmallestTerm(X);
- r = base->width;
- if(r > minwidth){ //there is no optimal solution.
- return -2;
- }
- else if(r == minwidth){
- X -= minwidth;
- base++;
- }else{ //merge the smallest width and insert it into the original array
- if(r < (1<<(MaxHuffLen-1))){
- start = base+1; r_Num = 1;
- //find start and end
- while(start->width < 2*r && start <= Last){
- r_Num++;
- start++;
- }
- end = start;
- while(end->width == 2*r && end <= Last){
- end++;
- }
- end--;
- //move back the (>=2*r)width node
- node = Last; r_Num = r_Num/2;
- while(node >= start){
- *(node+r_Num) = *node;
- node--;
- }
- //package and merge
- node = start;
- start = start + r_Num;
- end = end + r_Num;
- for(i=0;i<r_Num;i++){
- left = base; base++;
- right = base; base++;
- weight = left->weight + right->weight;
- while(start <= end && start->weight <= weight){
- *node = *start;
- start++;
- node++;
- }
- node->weight = weight; node->width = 2*r;
- node->left = left; node->right = right;
- node++;
- }
- if(base->width == r){ //if r_Num is odd,remove the last r(width) Node.
- RemoveNodeMark(base,Flag,Symbols);
- base++;
- }
- Last += r_Num;
- }else{ //r >= (1<<(MaxHuffLen-1))
- while(base->width == r){
- left = base; weight = base->weight;
- if((*(base+1)).width == r){
- base++;
- right = base; weight += base->weight;
- base++;
- Last++;
- Last->weight = weight; Last->width = 2*r;
- Last->left = left; Last->right = right;
- }else{
- RemoveNodeMark(base,Flag,Symbols);
- base++;
- }
- }
- }
- }
- }
- //output the HuffCode
- GenerateHuffmanCode(HuffCode,Flag,MaxHuffLen,Symbols,SortIndex);
- //print HuffCode
- for(i=0;i<Symbols;i++){
- printf("%03d weight:%04d Code:",HuffCode[i].index,Freq[i]);
- PrintHuffCode(HuffCode[i]);
- printf("\tCodeLen:%02d",HuffCode[i].len);
- printf("\n");
- }
- bitspersymbols = BitsPerSymbol(HuffCode,Freq,Symbols,WeightSum);
- printf("average code length:%f bits/symbol.\n",bitspersymbols);
- free(tree); tree = NULL;
- free(Flag); Flag = NULL;
- return 0;
- }
- #include <time.h>
- int main()
- {
- // int Freq[MaxSymbols] = {1,25,3,4,9,6,4,6,26,15,234,4578}; //weight is not zero.
- int Freq[MaxSymbols] = {10,6,2,1,1}; //weight is not zero.
- GenLenLimitedOptHuffCode(Freq,5); //5,12
- return 0;
- }
输出结果例如以下所看到的:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHltcXE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
基于二叉树和数组实现限制长度的最优Huffman编码的更多相关文章
- 基于二叉树和双向链表实现限制长度的最优Huffman编码
该代码採用二叉树结合双向链表实现了限制长度的最优Huffman编码,本文代码中的权重所有採用整数值表示.http://pan.baidu.com/s/1mgHn8lq 算法原理详见:A fast al ...
- "《算法导论》之‘线性表’":基于动态分配的数组的顺序表
我们利用静态分配的数组来实现的顺序表的局限还是挺大的,主要在于它的容量是预先定好的,用户不能根据自己的需要来改变.如果为了后续用户能够自己调整顺序表的大小,动态地分配数组空间还是很有必要的.基于动态分 ...
- JavaScript移除数组元素减少长度的方法
JavaScript移除数组元素减少长度的方法,代码如下: //数组移除长度方法 var array=[]; array[0]="张三"; array[1]="李四& ...
- js获取对象、数组的实际长度,元素实际个数
/*获取对象.数组的长度.元素个数 *@param obj 要计算长度的元素,可以为object.array.string */ function count(obj){ var objType = ...
- 关于String类和String[]数组的获取长度方法细节
一.在Java中,以下代码段有错误的是第( )行 public static void main(String[] args) { String name = "小新"; ...
- Android For JNI(四)——C的数组,指针长度,堆内存和栈内存,malloc,学生管理系统
Android For JNI(四)--C的数组,指针长度,堆内存和栈内存,malloc,学生管理系统 好几天每写JNI了,现在任务也越来越重了,工作的强度有点高,还有好几个系列的博客要等着更新,几本 ...
- C# 出现base-64 字符数组的无效长度的解决办法
最近的一个项目,在传递参数时,在Win2003上正常,在Win7下抛出“base-64 字符数组的无效长度”这样的错误 对比了一下经过Convert.ToBase64String()转换过的参数发现, ...
- 坐标轴刻度取值算法-基于魔数数组-源于echarts的y轴刻度计算需求
本文链接:https://blog.csdn.net/qq_26909801/article/details/96966372数值型坐标轴刻度计算算法前言算法描述上代码代码运行效果结语前言因实习的公司 ...
- 三 基于Java动态数组手写队列
手写队列: package dataStucture2.stackandqueue; import com.lt.datastructure.MaxHeap.Queue; import dataStu ...
随机推荐
- javascripts小结
1 NAN-isNaN():判断是否数值 2 数值转换 Number()-任何数据类型,parseInt(),parseFloat()-字符串 3数组转字符串 var a=["red&quo ...
- Linux命令压缩与解压缩
zip格式的文件:zip和unzip zip 命令: # zip test.zip test.txt 它会将 test.txt 文件压缩为 test.zip ,当然也可以指定压缩包的目录,例如 /ro ...
- NOIP2015
现在来总结一下. 斗地主 这题的题目描述感觉不太清晰,当时有很多人去问,但都没有得到任何回应.好吧,虽然我也是似懂非懂,但是就算看清楚了题目又能怎么样呢. 首先这题只能够搜索吧,或者说是DP,不过有很 ...
- Android中通过进程注入技术改动广播接收器的优先级
前言 这个周末又没有吊事,在家研究了怎样通过进程的注入技术改动广播接收器的优先级.关于这个应用场景是非常多的.并且也非常重要.所以就非常急的去fixed了. Android中的四大组件中有一个广播:B ...
- linux命令--sysctl
sysctl sysctl被用来在执行时配置内核参数.这些参数都存储在/proc/sys/(以键-值对形式存储)中.你可以用sysctl来读和写数据 命令参数 variable 要读的键值的名字 ...
- ActionBar点击弹出下拉框操作
首先: getActionBar().setDisplayShowTitleEnabled(false); ActionBar.LayoutParams lp = new ActionBar.Layo ...
- [ArcGIS必打补丁]ArcGIS 10.1 SP1 for (Desktop, Engine, Server) Quality Improvement Patch
大家都知道假设希望保证企业级GIS系统的稳定执行,除了使用最新的ArcGIS版本号产品以外,还须要打上相关的补丁. 补丁分为:Service Pack和Patch 比如,假设你使用的ArcGIS10. ...
- 从数据库中,绑定JQuery Accordion控件---Repeater control
http://aspsnippets.com/Articles/jQuery-Accordion-example-in-ASPNet-using-C-and-VBNet.aspx 1. 添加JQuer ...
- ADO.NET 总结
一.简单介绍ADO.NET System.Data:DataTable,DataSet,DataRow,DataColumn,DataRelation,Constraint System.Data.C ...
- 从零搭建LNMP环境
Linux就是环境所在的操作系统: Nginx则是一个「高性能的HTTP和反向代理服务器」,官网地址:http://nginx.org/: MySQL则是一个方便地对数据进行增删改查的数据库管理系统, ...