📄 huffman.c
字号:
/*
* Definition for Huffman coding
*
* vim: ts=4 sw=4 cindent nowrap
*/
#include <stdlib.h>
#include <stdio.h>
#include "bitio.h"
typedef struct{
unsigned long count;
int parent, lchild, rchild;
} HNODE;
HNODE hTree[512];
typedef struct{
unsigned long code;
int codelength;
} HCODE;
HCODE hCode[256];
unsigned long counts[256];
void BuildCounts( FILE *fp);
int BuildTree( void);
void BuildCode( void);
void HuffmanEncode( FILE *fp, BITFILE *bf);
void HuffmanDecode( BITFILE *bf, FILE *fp);
void BuildCounts( FILE *fp){
int c;
for( c=0; c<256; c++) counts[c] = 0;
while( EOF!=(c=fgetc(fp))) counts[c]++;
}
int BuildTree( void){
int i;
int min1, min2, nextfree;
for( i=0; i<256; i++){
hTree[i].count = counts[i];
hTree[i].parent = 0;
hTree[i].lchild = 0;
hTree[i].rchild = 0;
}
for( i=256; i<512; i++){
hTree[i].count = 0;
hTree[i].parent = 0;
hTree[i].lchild = 0;
hTree[i].rchild = 0;
}
hTree[511].count = 0xFFFFFFFFL;
nextfree = 256;
for( ;;nextfree++){
min1=min2=511;
for( i=0; i<nextfree; i++){
if( 0<hTree[i].count && 0==hTree[i].parent){ // free node
// update min1,min2, for min1, min2 and i
if( hTree[i].count < hTree[min1].count){
min2=min1;
min1=i;
}else if( hTree[i].count < hTree[min2].count){
min2=i;
}
}
}
if( 511==min2) break; //done if only one node left( the root)
// now min1,min2 are the least weighted nodes before nextfree
// update nextfree as parents of min1,min2
hTree[nextfree].count = hTree[min1].count + hTree[min2].count;
hTree[nextfree].lchild = min1;
hTree[nextfree].rchild = min2;
// min1 and min2 need to be updated too
hTree[min1].parent = nextfree;
hTree[min2].parent = nextfree;
}
nextfree --;
return nextfree;
}
void BuildCode( void){
unsigned long code;
unsigned long mask;
int n, codelength;
int currentNode, parentNode;
for( n=0; n<256; n++){
codelength = 0;
code = 0;
mask = 1;
for( currentNode=n, parentNode=hTree[currentNode].parent;
0!=parentNode;
currentNode=parentNode, parentNode=hTree[parentNode].parent){
if( currentNode == hTree[parentNode].rchild)
code |= mask;
mask <<= 1;
codelength++;
}
hCode[n].code = code;
hCode[n].codelength = codelength;
}
}
void HuffmanEncode( FILE *fp, BITFILE *bf){
unsigned long filelength;
int i;
BuildCounts( fp);
fseek( fp, 0, SEEK_END);
filelength = ftell( fp);
BitsOutput( bf, filelength, 4*8);
for( i=0; i<256; i++) BitsOutput( bf, counts[i], 4*8);
BuildTree( );
BuildCode( );
fseek( fp, 0, SEEK_SET);
while( EOF!=(i=fgetc(fp))){
BitsOutput( bf, hCode[i].code, hCode[i].codelength);
}
}
void HuffmanDecode( BITFILE *bf, FILE *fp){
unsigned long filelength;
int i;
int rootNode;
int node;
filelength = BitsInput( bf, 4*8);
if( -1 == filelength) filelength = 0;
// reading the counts
for( i=0; i<256; i++) counts[i] = BitsInput( bf, 4*8);
rootNode = BuildTree( );
while( 0<filelength){
node = rootNode;
do{
if( 0 == BitInput( bf)) node = hTree[node].lchild;
else node = hTree[node].rchild;
}while( 255<node);
fputc( node, fp);
filelength --;
}
}
int main( int argc, char **argv){
FILE *fp;
BITFILE *bf;
if( 4>argc){
fprintf( stdout, "usage: %s <o> <ifile> <ofile>\n", argv[0]);
fprintf( stdout, "\t<o>: E or D reffers encode or decode\n");
fprintf( stdout, "\t<ifile>: input file name\n");
fprintf( stdout, "\t<ofile>: output file name\n");
return -1;
}
if( 'E' == argv[1][0]){ // do encoding
fp = fopen( argv[2], "rb");
bf = OpenBitFileOutput( argv[3]);
if( NULL!=fp && NULL!=bf){
HuffmanEncode( fp, bf);
fclose( fp);
CloseBitFileOutput( bf);
fprintf( stdout, "encoding done\n");
}
}else if( 'D' == argv[1][0]){ // do decoding
bf = OpenBitFileInput( argv[2]);
fp = fopen( argv[3], "wb");
if( NULL!=fp && NULL!=bf){
HuffmanDecode( bf, fp);
fclose( fp);
CloseBitFileInput( bf);
fprintf( stdout, "decoding done\n");
}
}else{ // otherwise
fprintf( stderr, "not supported operation\n");
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -