基于二叉树和数组实现限制长度的最优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 ...
随机推荐
- java的for循环问题的解决,以及安卓中ListView插入数据的问题
package test.testdemo; import org.springframework.jdbc.core.JdbcTemplate; import com.util.Pub; publi ...
- dede修改移动文档的js
dede后台弹框修改: 想做个类似文章列表的移动功能,弹框,然后修改成功到表 先在list.js里复制一份moveArc的方法,到archives_do.php里复制一份moveArchives的方法 ...
- QT图片旋转
目前发现有两种方法,如下: 1.使用QPixmap的transformed函数旋转,这个函数默认是以图片中心为旋转点,不能随意设置旋转点,使用如下: QMatrix leftmatrix; leftm ...
- 汇总:Linux下10款即时通讯客户端,skype
aMSN 是一款功能强大的MSN(WLM)的客户端,支持皮肤.插件.系统托盘图标.摄像头.多帐号登录.离线信息等. Pidgin 不用说了,是GNOME下的IM客户端,支持AIM, Google Ta ...
- HNOI2016 网络
题目 朴素算法 在线. 树链剖分套一个堆. 时间复杂度\(O(n (\log n)^3)\). 分治 朴素算法中,套一个堆是为了支持删除操作. 采用以下分治可以避免删除操作: 每次对时间\([l,r] ...
- POJ 2050 Searching the Web
题意简述:做一个极其简单的搜索系统,对以下四种输入进行分析与搜索: 1. 只有一个单词:如 term, 只需找到含有这个单词的document,然后把这个document的含有这个单词term的那些行 ...
- paip.php-gtk 桌面程序 helloworld总结
paip.php-gtk 桌面程序 helloworld总结 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.cs ...
- 《Android第一行代码》笔记
学习Android开发差点儿相同有两年时间了.期间也做了大大小小的一些项目.近来抽出闲暇想把Android基础强化一下,之前在网上看到了郭霖郭大神的几篇博客.从中受益不少.于是花了近一周时间看完了郭神 ...
- Python相关项目和技术
下面的项目是<Learn PYTHON the hard way>里面的,以后可能会补充: 1.Django,创建web程序的框架:https://www.djangoproject.co ...
- [Swust OJ 249]--凸包面积
题目链接: http://acm.swust.edu.cn/problem/0249/ 麦兜是个淘气的孩子.一天,他在玩钢笔的时候把墨水洒在了白色的墙上.再过一会,麦兜妈就要回来了, ...