开发一个控制台程序,使用Huffnan压缩算法对bmp格式图片文件进行压缩
项目结构
运行结果
Huffman.h
#pragma once
#include <iostream>
using namespace std;
struct HTNode
{
int weight= 0 ;
int parent= 0 ;
int lchild= 0 ;
int rchild= 0 ;
} ;
typedef HTNode * Huffmantree;
typedef char * * HuffmanCode;
int HuffmanTree ( Huffmantree & pHT, int * w, int n) ;
int Select ( Huffmantree pHT, int nSize) ;
void TestHuffmanTree ( Huffmantree pHT) ;
int HuffmanCoding ( HuffmanCode& pHC, Huffmantree& pHT) ;
void TestHuffmanCode ( int root, Huffmantree pHT, HuffmanCode pHC) ;
Compress.h
#pragma once
#include "Huffman.h"
#define SIZE 256
struct HEAD {
char type[ 8 ] ;
int length;
int weight[ 256 ] ;
} ;
typedef char * BUFFER;
int InitHead ( const char * pFilename, HEAD& sHead) ;
int Compress ( const char * pFilename) ;
int Str2byte ( const char * pBinStr) ;
int Encode ( const char * pFilename, const HuffmanCode pHC, char * pBuffer, const int nSize) ;
int WriteFile ( const char * pFilename, const HEAD sHead, const BUFFER pBuffer, const int nSize) ;
Huffman.cpp
#include "Huffman.h"
int HuffmanTree ( Huffmantree & pHT, int * w, int n) {
for ( int i = 0 ; i < n * 2 ; i++ )
pHT[ i] = { 0 , 0 , 0 , 0 } ;
for ( int i = 0 ; i < n; i++ ) {
pHT[ i + 1 ] . weight = w[ i] ;
}
for ( int i = n; i < n * 2 ; i++ ) {
pHT[ i + 1 ] . lchild = Select ( pHT, i) ;
pHT[ i + 1 ] . weight + = pHT[ Select ( pHT, i) ] . weight;
pHT[ Select ( pHT, i) ] . parent = i + 1 ;
pHT[ i + 1 ] . rchild = Select ( pHT, i) ;
pHT[ i + 1 ] . weight + = pHT[ Select ( pHT, i) ] . weight;
pHT[ Select ( pHT, i) ] . parent = i + 1 ;
}
return 0 ;
}
int Select ( Huffmantree pHT, int nSize) {
int minValue = 0x7FFFFFFF ;
int min = 0 ;
for ( int i = 1 ; i <= nSize; i++ ) {
if ( pHT[ i] . parent == 0 && pHT[ i] . weight < minValue) {
minValue = pHT[ i] . weight;
min = i;
}
}
return min;
}
void TestHuffmanTree ( Huffmantree pHT) {
for ( int i = 1 ; i < 512 ; i++ ) {
printf ( "pHT[%d] \t %d \t %d \t %d \t %d \n" , i, pHT[ i] . weight, pHT[ i] . parent, pHT[ i] . lchild, pHT[ i] . rchild) ;
}
}
int HuffmanCoding ( HuffmanCode& pHC, Huffmantree& pHT) {
char cd[ 256 ] = { '\0' } ;
int cdlen = 0 ;
for ( int i = 1 ; i < 512 ; i++ ) {
pHT[ i] . weight = 0 ;
}
int p = 511 ;
while ( p != 0 ) {
if ( pHT[ p] . weight == 0 ) {
pHT[ p] . weight = 1 ;
if ( pHT[ p] . lchild != 0 ) {
p = pHT[ p] . lchild;
cd[ cdlen++ ] = '0' ;
}
else if ( pHT[ p] . rchild == 0 )
{
pHC[ p] = ( char * ) malloc ( ( cdlen + 1 ) * sizeof ( char ) ) ;
cd[ cdlen] = '\0' ;
strcpy ( pHC[ p] , cd) ;
}
}
else if ( pHT[ p] . weight == 1 ) {
pHT[ p] . weight = 2 ;
if ( pHT[ p] . rchild != 0 )
{
p = pHT[ p] . rchild;
cd[ cdlen++ ] = '1' ;
}
}
else
{
pHT[ p] . weight = 0 ;
p = pHT[ p] . parent;
-- cdlen;
}
}
return 0 ;
}
void TestHuffmanCode ( int root, Huffmantree pHT, HuffmanCode pHC) {
if ( pHT[ root] . lchild == 0 && pHT[ root] . rchild == 0 ) {
printf ( "0x%02X %s\n" , root - 1 , pHC[ root] ) ;
}
if ( pHT[ root] . lchild)
{
TestHuffmanCode ( pHT[ root] . lchild, pHT, pHC) ;
}
if ( pHT[ root] . rchild)
{
TestHuffmanCode ( pHT[ root] . rchild, pHT, pHC) ;
}
}
Compress.cpp
#include "Compress.h"
#include "Huffman.h"
int Compress ( const char * pFilename) {
int weight[ 256 ] = { 0 } ;
FILE* in = fopen ( pFilename, "rb" ) ;
int ch;
while ( ( ch = getc ( in) ) != EOF ) {
weight[ ch] ++ ;
}
fclose ( in) ;
HTNode* pHT = ( HTNode* ) malloc ( 512 * sizeof ( HTNode) ) ;
HuffmanCode pHC = ( char * * ) malloc ( 257 * sizeof ( char * ) ) ;
HuffmanTree ( pHT, weight, 256 ) ;
HuffmanCoding ( pHC, pHT) ;
int nSize = 0 ;
for ( int i = 0 ; i < 256 ; i++ ) {
nSize + = weight[ i] * strlen ( pHC[ i+ 1 ] ) ;
}
nSize = ( nSize % 8 ) ? nSize / 8 + 1 : nSize / 8 ;
char * pBuffer = NULL ;
Encode ( pFilename, pHC, pBuffer, nSize) ;
return 0 ;
}
int Str2byte ( const char * pBinStr) {
char b = 0x00 ;
for ( int i = 0 ; i < 8 ; i++ ) {
b = b << 1 ;
if ( pBinStr[ i] == '1' ) {
b= b| 0x01 ;
}
}
return b;
}
int strlen2 ( char * x) {
int i = 0 ;
while ( x[ i] == '0' || x[ i] == '1' ) {
i++ ;
}
return i;
}
int Encode ( const char * pFilename, const HuffmanCode pHC, char * pBuffer, const int nSize) {
FILE* in = fopen ( pFilename, "rb" ) ;
pBuffer = ( char * ) malloc ( nSize * sizeof ( char ) ) ;
if ( ! pBuffer) {
cerr << "开辟缓冲区失败" << endl;
return 0 ;
}
char cd[ SIZE] = { 0 } ;
int pos = 0 ;
int ch;
while ( ( ch = fgetc ( in) ) != EOF )
{
strcat ( cd, pHC[ ch+ 1 ] ) ;
while ( strlen2 ( cd) >= 8 ) {
pBuffer[ pos++ ] = Str2byte ( cd) ;
for ( int i = 0 ; i < SIZE - 8 ; i++ ) {
cd[ i] = cd[ 8 + i] ;
}
}
}
if ( strlen ( cd) > 0 ) {
pBuffer[ pos++ ] = Str2byte ( cd) ;
}
fclose ( in) ;
HEAD sHead;
InitHead ( pFilename, sHead) ;
WriteFile ( pFilename, sHead, pBuffer, nSize) ;
}
int InitHead ( const char * pFilename, HEAD& sHead) {
strcpy ( sHead. type, "HUF" ) ;
sHead. length = 0 ;
for ( int i = 0 ; i < SIZE; i++ ) {
sHead. weight[ i] = 0 ;
}
FILE* in = fopen ( pFilename, "rb" ) ;
int ch;
while ( ( ch = getc ( in) ) != EOF ) {
sHead. weight[ ch] ++ ;
sHead. length++ ;
}
fclose ( in) ;
in = NULL ;
return 0 ;
}
int WriteFile ( const char * pFilename, const HEAD sHead, const BUFFER pBuffer, const int nSize) {
char filename[ SIZE] = { 0 } ;
strcpy ( filename, pFilename) ;
strcat ( filename, ".huf" ) ;
FILE* out = fopen ( filename, "wb" ) ;
fwrite ( & sHead, sizeof ( HEAD) , 1 , out) ;
fwrite ( pBuffer, sizeof ( char ) , nSize, out) ;
fclose ( out) ;
out = NULL ;
cout << sHead. length<< " 字节" << endl;
cout << "生成压缩文件: " << filename << endl;
int len = sizeof ( HEAD) + strlen ( pFilename) + 1 + nSize;
cout << len << " 字节" << endl;
cout << "压缩比率: " << len * 1.0 / ( sHead. length * 1.0 ) * 100 << "%" << endl;
return len;
}
Main.cpp
#include "Compress.h"
using namespace std;
int main ( ) {
cout << "==========Huffman文件压缩==========" << endl;
char name[ 100 ] ;
cout << "请输入文件名: " ;
cin >> name;
Compress ( name) ;
return 0 ;
}