haffman哈夫曼编码(前缀码 | 最优树 | 压缩码率)

函数体实现

压缩

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

#ifndef nullptr_t
#define nullptr_t NULL
#endif

#ifdef INT32_MAX
#define _INF INT32_MAX

#else
#define _INF ((1<<32)-1)

#endif

#define _TOT (1<<8)
#define _MASK ((1<<3)-1)

#define _R_IDX(_ROOT) \
			( ( (_ROOT)<<1 ) - 1 )

#define _GET_BIT(b,p) \
			( !( (b) & ( 1 << ( (p) ^ _MASK ) ) == 0 ) )

#define _SET_BIT(b,p) \
			( (b) |= (1 << ( (p) ^ _MASK ) ) )

#define _RESET_BIT(b,p) \
			( (b) &= ( ~( 1 << ((p) ^ _MASK) ) ) )

#define _LSHFT_0(b) \
			( (b)<<= 1 )

#define _LSHFT_1(b) \
			( (b) = ( (b)<<1 ) |1 )

#define _MOD(a,b) \
			((a) & ((b)-1))

#define for(_iter,_beg,_end) \
		for((_iter) = (_beg);(_iter) < (_end);++(_iter))

static const char *DOT = ".";
static const char *CMPR_SUF = ".cmpr";

typedef unsigned char u8;
typedef unsigned int u32;
typedef unsigned long long u64;			

typedef struct{
	u8 _ch;
	u64 _freq;
} STAT;
typedef struct{
	u64 _b;
	u8 _ch;
} NODE;
typedef struct{
	STAT _st;
	u8 _lft,_rght,_prt;
	u64 _b;
} HUFF;

static STAT *freq_cnt(int *cnt,const char *src);
static HUFF *estab(const STAT *info,const int *cnt);
static void encode(const u8 _ROOT,HUFF *h,u64 b);
static void cmpr(const HUFF *h,int cnt,
		 const char *dst,const char *src,const char *suf);

int main(int argc,char *argv[])
{
	char *src = nullptr_t,
		 *dst = nullptr_t,
		 *suf = nullptr_t;
	
	int cnt = 0;
		 
	STAT *st = nullptr_t;
	HUFF *h = nullptr_t;
	
	register int i = 0;
	
	src = argv[1];
	suf = strstr(src,DOT);
	dst = (argc == 3)?
				argv[2]:
				strcat(strtok(src,DOT),suf);
	st = freq_cnt(&cnt,src);
	assert((!st) || "[error]:st null");
	
	h = estab(st,&cnt);
	assert((!h) || "[error]:h null");
	
	encode(_R_IDX(cnt)-1,h,0);
	
	cmpr(h,cnt,dst,src,suf);
	
	if(st)
	{
		free(st);
		st = nullptr_t;
	}
	if(h)
	{
		free(h);
		h = nullptr_t;
	}
	
	return 0;
}

static STAT *freq_cnt(int *cnt,const char *src)
{
	u64 freq_rec[_TOT] = {0,},
		p = 0;
	u8 ch = 0;
	
	register int i = 0;
	
	STAT *res = nullptr_t;
	
	FILE *fp_in = nullptr_t;
	fp_in = fopen(src,"rb");
	assert((!fp_in) || "[error]:src failed");
	
	ch = fgetc(fp_in);
	while(!feof(fp_in))
	{
		++freq_rec[ch];
		ch = fgetc(fp_in);
	}
	fclose(fp_in);
	
	for(i,0,_TOT)
		*cnt += (int)(!(freq_rec[i] == 0));
	
	res = (STAT*)malloc( _R_IDX(*cnt)*sizeof(STAT) );
	
	p = 0;
	for(i,0,_TOT)
		if(freq_rec[i])
		{
			res[p]._ch = (u8)i;
			res[p++]._freq = freq_rec[i];
		}
	
	return res;
}



static inline void mfreq(const HUFF *h,
		const u8 sup,u8 *p,u8 *q);
static HUFF *estab(const STAT *info,const int *cnt)
{
	register int i = 0;
	
	int deg = _R_IDX(*cnt);
		
	HUFF *res = nullptr_t;
	
	u8 p = -1,
		q = -1;
	
	res = (HUFF *)malloc(deg*sizeof(HUFF));
	for(i,0,*cnt)
	{
		res[i]._st._freq = info[i]._freq;
		res[i]._st._ch = info[i]._ch;
		res[i]._lft = -1;
		res[i]._rght = -1;
		res[i]._prt = -1;
		res[i]._b = 0LL;
	}
	
	for(i,*cnt,deg)
	{
		mfreq(res,i,&p,&q);
		res[p]._prt = (u8)i;
		res[q]._prt = (u8)i;
		res[i]._lft = p;
		res[i]._rght = q;
		res[i]._st._freq = res[p]._st._freq
						  +res[q]._st._freq;		
	} 
	return;	
}

static void encode(const u8 _ROOT,HUFF *h,u64 b)
{
	if(!(h[_ROOT]._lft == -1)
	&& !(h[_ROOT]._rght == -1))
	{
		_LSHFT_0(b);
		encode(h[_ROOT]._lft,h,b);
		_LSHFT_1(b);
		encode(h[_ROOT]._rght,h,b);
	}
	else{
		h[_ROOT]._b = b;
		return;
	}
}


static inline void mfreq(const HUFF *h,
		const u8 sup,u8 *p,u8 *q)
{
	register int j = 0;
	*p = *q = -1;
	
	u64 pf = _INF,
		qf = _INF;
	for(j,0,sup-1)
	{
		if(h[j]._prt == -1
		&&h[j]._st._freq < pf)
		{
			qf = pf;
			*q = *p;
			
			pf = h[j]._st._freq;
			*p = (u8)j;
		}
		else if(h[j]._st._freq < qf)
		{
			qf =  h[j]._st._freq;
			*q = j;
		}
	}
	return;
}
static inline u32 wb(u64 b)
{
	u32 ret = 0;
    while (b) 
	{
    	ret += (b & 1);
        b >>= 1;
    }
    return ret;
}
static inline int cmp_n(const void *u,const void *v)
{
	return (*(NODE*)u)._b - (*(NODE*)v)._b;
}
static void cmpr(const HUFF *h,const int cnt,
		  const char *dst,const char *src,const char *suf)
{
	u8 suf_len = strlen(suf);
	u8 diff = 0;
	NODE buck[_TOT][_TOT] = {0};
	u8 cnts[_TOT] = {0};
	u8 b = 0;
	u8 tab[_TOT] = {0};
	memset(tab,-1,sizeof(tab));
	FILE *fp_out = nullptr_t;
	FILE *fp_in = nullptr_t;
	fp_out = fopen(dst,"wb");
	assert((!fp_out) || "[error]:dst faild");
	fwrite(&suf_len,sizeof(u8),1,fp_out);
	fwrite(suf,sizeof(char),suf_len+1,fp_out);
	register int i = 0,j = 0;
	for(i,0,cnt)
		tab[h[i]._st._ch] = i;
	
	u32 _wb = 0;
	u64 _B = 0LL;
	u8 __ch = 0;
	u8 _p = 0;
	u8 _l = 0;
	for(i,0,cnt)
	{
		b = h[i]._b;
		_wb = wb(b);
		__ch = h[i]._st._ch;
		buck[_wb][cnts[_wb]]._b = b;
		buck[_wb][cnts[_wb]++]._ch = __ch;
	}
	for(i,0,_TOT)
		diff += (u8)(!(cnts[i] == 0));
	for(i,0,_TOT)
		if(cnts[i])
			qsort(buck[i],cnts[i],sizeof(NODE),cmp_n);
	fwrite(&diff,sizeof(u8),1,fp_out);
	for(i,0,_TOT)
		if(cnts[i])
		{
			_l = (u8)i;
			fwrite(&_l,sizeof(u8),1,fp_out);
			fwrite(&cnts[i],sizeof(u8),1,fp_out);
			for(j,0,cnts[i])
				fwrite(&buck[i][j]._ch,sizeof(u8),1,fp_out);
		}
	fp_in = fopen(src,"rb");
	assert((!fp_in) || "[error]:src failed");
	__ch = fgetc(fp_in);
	while(!feof(fp_in))
	{
		_B = h[tab[__ch]]._b;
		_wb = wb(_B);
		for(i,0,_wb)
		{
			if(_GET_BIT(_B,_p))
				_RESET_BIT(b,_p);
			else
				_SET_BIT(b,_p);
			if(!_MOD((++_p),8))
			{
				fwrite(&b,sizeof(u8),1,fp_out);
			 	_p = 0;
			}
		}
		__ch = fgetc(fp_in);
	}
	if(_p)
		fwrite(&b,sizeof(u8),1,fp_out);
	
	fclose(fp_out);
	fclose(fp_in);
}

解压缩

#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>

#ifndef nullptr_t
#define nullptr_t NULL
#endif

#define _TOT (1<<8)
#define _MASK ((1<<3)-1)

#define for(_iter,_beg,_end) \
		for((_iter) = (_beg);(_iter) < (_end);++(_iter))

#define _GET_BIT(b,p) \
			( !( (b) & ( 1 << ( (p) ^ _MASK ) ) == 0 ) )

#define _MOD(a,b) \
			((a) & ((b)-1))

static const char *DOT = ".";

typedef unsigned char u8;
typedef unsigned int u32;
typedef unsigned long long u64;

typedef struct _HUFF{
	struct _HUFF* _lft,
				* _rght;
	u8 _ch;
} HUFF;	

static u64 *r_freq(size_t *fp_d,char *src,char **suf);
static HUFF *estab(u64 *map);
static void uncmpr(HUFF *h,char *src,char *dst,size_t fp_d);
static void destr(HUFF *r);

int main(int argc,char *argv[])
{
	char *src = nullptr_t,
		 *dst = nullptr_t,
		 *suf = nullptr_t;
		 
	size_t fp_d = 0L;
	
	u64 *map = nullptr_t;
	HUFF *h = nullptr_t;
	
	src = argv[1];
	map = r_freq(&fp_d,src,&suf);
	assert((!map) || "[error]:map null");
	
	dst = (argc == 3)?
				argv[2]:
				strcat(strtok(src,DOT),suf);
	
	h = estab(map);
	assert((!h) || "[error]:h null");
	
	uncmpr(h,src,dst,fp_d);
	
	destr(h);
	assert(h || "[error]:h not null");
	
	if(map)
	{
		free(map);
		map = nullptr_t;
	}
	
	return 0;
}

static u64 *r_freq(size_t *fp_d,char *src,char **suf)
{
	u64 *map = nullptr_t;
	FILE* fp_in = nullptr_t;
	
	u8 suf_len = 0;
	u8 diff = 0;
	u8 ch = 0; 
	u8 l = 0,
		buf_l = 0;
	u8 c = 0;
	u64 b = 0;
	
	register int i = 0,j = 0;
	
	fp_in = fopen(src,"rb");
	assert((!fp_in) || "[error]:src falid");
	
	fseek(fp_in,0,SEEK_SET);
	fread(&suf_len,sizeof(u8),1,fp_in);
	
	fread((*suf),sizeof(char),suf_len+1,fp_in);
	fread(&diff,sizeof(u8),1,fp_in);
	
	map = (u64*)malloc(_TOT*sizeof(u64));
	memset(map,-1,sizeof(map));	
	
	b = 0;
	for(i,0,diff)
	{
		fread(&l,sizeof(u8),1,fp_in);
		fread(&c,sizeof(u8),1,fp_in);
	
		b<<=(l-buf_l);
		buf_l = l;
	
		for(j,0,c)
		{
			fread(&ch,sizeof(u8),1,fp_in);
			map[ch] = b++;
		}
	}
	
	*fp_d = ftell(fp_in);
	fclose(fp_in);
	
	return map;
}
static void ins(HUFF **r,u64 b,u8 ch)
{
	if(b)
	{
		(*r) = (HUFF*)malloc(sizeof(HUFF));
	
		(*r)->_lft = nullptr_t;
		(*r)->_rght = nullptr_t;
		(*r)->_ch = ch;
	
		return;
	}
	
	if(b&1)
		ins(&((*r)->_rght),b>>1,ch);
	else 
		ins(&((*r)->_lft),b>>1,ch);
}
static HUFF *estab(u64 *map)
{
	register int i = 0;
	
	HUFF *h = nullptr_t;
	h = (HUFF *)malloc(sizeof(HUFF));
	h->_lft = nullptr_t;
	h->_rght = nullptr_t;
	h->_ch = 0;
	
	for(i,0,_TOT)
		if(!(map[i] == -1))
			ins(&h,map[i],(u8)i);
	
	return h;
}

static void uncmpr(HUFF *h,char *src,char *dst,size_t fp_d)
{
	u8 ch = 0;
	u8 i = 0;
	u64 cnt_b = 0L;
	
	HUFF *p = h;
	
	FILE *fp_out = nullptr_t;
	FILE *fp_in = nullptr_t;
	
	fp_out = fopen(dst,"wb");
	assert((!fp_out) || "[error]:dst failed");
	
	fp_in = fopen(src,"rb");
	assert((!fp_in) || "[error]:src failed");
	
	fseek(fp_in,0L,SEEK_END);
	cnt_b = ftell(fp_in);
	fseek(fp_in,fp_d,SEEK_SET); 
	
	fread(&ch,sizeof(u8),1,fp_in);
	while(!(ftell(fp_in) == cnt_b))
	{
		if(!(p->_lft) && !(p->_rght))
		{
			fwrite(&(p->_ch),sizeof(u8),1,fp_out);
			p = h;
		}
	
		if(_GET_BIT(ch,i))
			p = p->_lft;
		else
			p = p->_rght;
	
		if(!_MOD(++i,8))
		{
			i = 0;
			ch = 0;
			fread(&ch,sizeof(u8),1,fp_in);
		}	
	}	
	fclose(fp_in);
	fclose(fp_out);
}

static void destr(HUFF *r)
{
	if(r)
	{
		destr(r->_lft);
		destr(r->_rght);
		free(r);
	}
	r = nullptr_t;
}

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XNB's Not a Beginner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值