//stack.h
/*************************************************************
FileName : stack.h
FileFunc : 定義棧頭文件
Version : V0.1
Author : Sunrier
Date : 2012-07-09 09:33:48
Descp : Linux下棧頭文件
*************************************************************/
#ifndef __STACK_H__
#define __STACK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "tree.h"
#define STACK_SIZE 128
#define STACK_INCREMENT_SIZE 128
typedef pTree ElemType;
typedef struct stack
{
ElemType *bottom;
int top;
int size;
}sStack,*pStack;
void init_stack(pStack *p);
int isEmpty(pStack p);
int isFull(pStack p);
int push(pStack,ElemType e);
int pop(pStack p,ElemType *e);
int getTop(pStack p,ElemType *e);
#ifdef __cplusplus
}
#endif
#endif
//stack.c
/*************************************************************
FileName : stack.c
FileFunc : 定義實現棧函數
Version : V0.1
Author : Sunrier
Date : 2012-07-09 09:33:29
Descp : Linux下實現棧函數
*************************************************************/
#include <stdlib.h>
#include "stack.h"
/*棧先進後出*/
void init_stack(pStack *p)
{
*p = malloc(sizeof(sStack));
(*p)->bottom = malloc(sizeof(ElemType)*STACK_SIZE);
(*p)->top = -1;
(*p)->size = STACK_SIZE;
}
/*判斷棧是否爲空*/
int isEmpty(pStack p)
{
if( -1==p->top )
return 1;
return 0;
}
/*判斷棧是否已滿*/
int isFull(pStack p)
{
if( (p->size-1)==p->top )
return 1;
return 0;
}
/*入棧*/
int push(pStack p,ElemType e)
{
if( isFull(p) )
{
p->bottom = realloc(p->bottom,(p->size+STACK_INCREMENT_SIZE)*sizeof(ElemType));
p->size += STACK_INCREMENT_SIZE;
}
p->top++;
p->bottom[p->top] = e;
return 1;
}
/*出棧*/
int pop(pStack p,ElemType *e)
{
if(isEmpty(p))
{
return 0;
}
*e = p->bottom[p->top];
p->top--;
return 1;
}
/*取棧頂數據*/
int getTop(pStack p,ElemType *e)
{
if( isEmpty(p) )
return -1;
*e = p->bottom[p->top];
return 1;
}
//queue.h
/*************************************************************
FileName : queue.h
FileFunc : 定義隊列頭文件
Version : V0.1
Author : Sunrier
Date : 2012-07-09 09:51:11
Descp : Linux下隊列頭文件
*************************************************************/
#ifndef __QUEUE_H__
#define __QUEUE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "tree.h"
typedef pTree QueueElem;
typedef struct queue
{
QueueElem data;
struct queue *next;
}sQueue, *pQueue;
void init_queue(pQueue *p, QueueElem data);
int push_queue(pQueue pq, QueueElem data);
int pop_queue(pQueue pq, QueueElem *data);
#ifdef __cplusplus
}
#endif
#endif
//queue.c
/*************************************************************
FileName : queue.c
FileFunc : 定義實現隊列函數
Version : V0.1
Author : Sunrier
Date : 2012-07-09 09:51:14
Descp : Linux下實現隊列函數
*************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
/*隊列先進先出*/
void init_queue(pQueue *p, QueueElem data)
{
*p = malloc(sizeof(sQueue));
(*p)->data = data;
(*p)->next = NULL;
}
/*進隊列,進來的數據放入隊列最後*/
int push_queue(pQueue pq, QueueElem ptree)
{
pQueue ptrav = pq, pnew;
if ( NULL==pq )
{
return 0;
}
while ( NULL!=ptrav->next )
{
ptrav = ptrav->next;
}
init_queue(&pnew, ptree);
ptrav->next = pnew;
return 1;
}
/*出隊列,把隊列中第一個數據出隊列*/
int pop_queue(pQueue pq, QueueElem *data)
{
pQueue pdel;
if ( pq == NULL )
{
return -1;
}
if ( pq->next == NULL )
{
return 0;
}
pdel = pq->next;
*data = pdel->data;
pq->next = pdel->next;
free(pdel);
return 1;
}
//tree.h
/*************************************************************
FileName : tree.h
FileFunc : 定義二叉樹頭文件
Version : V0.1
Author : Sunrier
Date : 2012-07-09 09:58:03
Descp : Linux下二叉樹頭文件
*************************************************************/
#ifndef __TREE_H__
#define __TREE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
typedef unsigned char etype;
typedef int type;
typedef struct TreeNode
{
etype data;
type count;
struct TreeNode *next;
struct TreeNode *left;
struct TreeNode *right;
}Tree,*pTree;
void Init_TreeNode(pTree *p);
void Init_eTreeNode(pTree *p,etype data);
int Read_File(pTree proot,FILE *pr,FILE *pw);
pTree Get_Frequency(pTree proot);
void Huffman(pTree *proot);
void Read_Huffman(pTree proot,int n,FILE *pr,FILE *pw);
void Create_Huffman(pTree proot,int ch,FILE *pr);
void ReHuffman(pTree proot,FILE *pr,FILE *pw,int count,int Num_Byte);
#ifdef __cplusplus
}
#endif
#endif
//tree.c
/*************************************************************
FileName : tree.c
FileFunc : 定義實現二叉樹函數
Version : V0.1
Author : Sunrier
Date : 2012-07-09 09:58:00
Descp : Linux下實現二叉樹函數
*************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "tree.h"
#include "stack.h"
#include "queue.h"
/*初始化樹的結點*/
void Init_TreeNode(pTree *p)
{
*p=malloc(sizeof(Tree));
(*p)->data = 0;
(*p)->count = 0;
(*p)->left = NULL;
(*p)->right = NULL;
(*p)->next = NULL;
}
/*初始化樹的結點數據*/
void Init_eTreeNode(pTree *p,etype data)
{
*p = malloc(sizeof(Tree));
(*p)->data = data;
(*p)->count = 1;;
(*p)->left = NULL;
(*p)->right = NULL;
(*p)->next = NULL;
}
/*取原文件數據構造樹型鏈表*/
int Read_File(pTree proot,FILE *pr,FILE *pw)
{
pTree p,pnew;
unsigned char ch;
if( NULL==proot )
return 0;
/*靜態統計模型*/
/*統計原始數據中各字符出現的頻率(即個數)*/
while( fread(&ch,sizeof(unsigned char),1,pr)>0 )
{
printf("%c",ch);
for(p=proot; p->next!=NULL; p=p->next)
{
if(p->next->data==ch)
{
(p->next->count)++;
break;
}
}
if( ( NULL==p->next) && (ch!=p->data) )
{
Init_eTreeNode(&pnew,ch);
p->next = pnew;
}
}
printf("\n");
int total = 0,num = 0;
/*統計原始數據中不同字符出現的個數以及所有字符出現的總的次數*/
for(p=proot->next; p!=NULL; p=p->next)
{
fwrite(&p->data,sizeof(char),1,pw);
fwrite(&p->count,sizeof(int),1,pw);
printf("%c:%d\n",p->data,p->count);
total += p->count;
num++;
}
printf("total:%d num:%d\n",total,num);
return num;
}
/*從樹型鏈表中找出字符頻率出現最小的結點*/
pTree Get_Frequency(pTree proot)
{
if( NULL==proot->next )
return NULL;
pTree p,ps = proot,min = proot->next,prev;
for(prev=proot; prev->next!=NULL; prev=prev->next)
{
p = prev->next;
if( p->count<min->count )
{
min = p;
ps = prev;
}
}
ps->next = min->next;
printf("huffman:%d",min->count);
return min;
}
/*構造最小二叉樹*/
void Huffman(pTree *proot)
{
pTree min1,min2;
pTree pnew,p;
while( ((min1=Get_Frequency(*proot))!=NULL) && ((min2=Get_Frequency(*proot))!=NULL) )
{
Init_TreeNode(&pnew);
puts("*");
pnew->left = min1;
pnew->right = min2;
pnew->count = min1->count+min2->count;
min1->next = pnew;
min2->next = pnew;
p = (*proot)->next;
(*proot)->next = pnew;
pnew->next = p;
}
free(*proot);
*proot = min1;
puts("----");
}
/*對二叉樹進行編碼,得到各個字符的編碼格式寫到壓縮後的文件中*/
void Read_Huffman(pTree proot,int n,FILE *pr,FILE *pw)
{
unsigned char bigcode = 0;
pTree pnew,pp,pc;
Init_eTreeNode(&pnew,0);
pStack ps;
init_stack(&ps);
pQueue p;
init_queue(&p,NULL);
int count = 0,Num_Byte = 1;
unsigned char ch;
while( fread(&ch,sizeof(char),1,pr)>0 )
{
push_queue(p,proot);
while( pop_queue(p,&pnew) )
{
if( NULL==pnew->left )
{
if( ch==pnew->data )/*找到隊列中的匹配字符*/
{
/*printf("ch = %c \n",ch);*/
while( NULL!=pnew )/*父結點全部壓棧,以便編碼*/
{
push(ps,pnew);
pnew=pnew->next;
}
pop(ps,&pp);
while( pop(ps,&pc) )
{
if( 8==count )
{
fwrite(&bigcode,sizeof(char),1,pw);
count = 0;
bigcode = 0;Num_Byte++;
}
if( pp->left==pc )/*判斷是左結點還是右結點,左結點上爲0,右結點上爲1*/
{
bigcode = (bigcode<<1)+0;
count++;
}
else
{
bigcode = (bigcode<<1)+1;
count++;
}
pp = pc;
}
while( pop_queue(p,&pnew) );/*其他字符全部出隊列*/
}
}
else
{
push_queue(p,pnew->right);
push_queue(p,pnew->left);
}
}
}
bigcode = bigcode<<(8-count);
fwrite(&bigcode,sizeof(char),1,pw);
printf("bigcode=%d\n",bigcode);
int info0 = n;
int info1 = count;
int info2 = Num_Byte;
fwrite(&info0,sizeof(int),1,pw);
fwrite(&info1,sizeof(int),1,pw);
fwrite(&info2,sizeof(int),1,pw);
}
/*取壓縮文件的數據構造樹型鏈表*/
void Create_Huffman(pTree proot,int ch,FILE *pr)
{
if( NULL==proot )
return ;
etype data;type count;
printf("ch=%d\n",ch);
pTree p = proot,pnew;
while( ch )
{
fread(&data,sizeof(etype),1,pr);
fread(&count,sizeof(type),1,pr);
Init_eTreeNode(&pnew,data);
pnew->data = data;
pnew->count = count;
p->next = pnew;
p = pnew;
ch--;
}
int total = 0,num = 0;
for(p=proot->next; p!=NULL; p=p->next)
{
total += p->count;
num++;
}
printf("total:%d num:%d\n",total,num);
}
/*取壓縮的文件二叉樹編碼,對其解壓數據*/
void ReHuffman(pTree proot,FILE *pr,FILE *pw,int count ,int Num_Byte)
{
pTree p = proot;
unsigned char ch,chcpy[8];
int n;
while( --Num_Byte&&fread(&ch,sizeof(unsigned char),1,pr)>0 )
{
printf("0x%x\n",ch);
chcpy[0] = ch&128;
chcpy[1] = ch&64;
chcpy[2] = ch&32;
chcpy[3] = ch&16;
chcpy[4] = ch&8;
chcpy[5] = ch&4;
chcpy[6] = ch&2;
chcpy[7] = ch&1;
for(n=0; n<8; n++)
printf("%d--",chcpy[n]);
n = 0;
while( n<8 )
{
if( NULL==p->left )
{
printf("\n%d\n",n);
printf("%d\n",chcpy[n]);
printf("%c\n",p->data);
fwrite(&p->data,sizeof(unsigned char ),1,pw);
p = proot;
continue;
}
if( chcpy[n] )
{
p = p->right;
}
else
{
p = p->left;
}
n++;
}
}
fread(&ch,sizeof(unsigned char),1,pr);
chcpy[0] = ch&128;
chcpy[1] = ch&64;
chcpy[2] = ch&32;
chcpy[3] = ch&16;
chcpy[4] = ch&8;
chcpy[5] = ch&4;
chcpy[6] = ch&2;
chcpy[7] = ch&1;
for(n=0; n<8; n++)
printf("%d--",chcpy[n]);
n = 0;
while( n<count )
{
if( NULL==p->left )
{
printf("%c:\n",p->data);
fwrite(&p->data,sizeof(char),1,pw);
p = proot;
continue;
}
if(chcpy[n])
{
p = p->right;
}
else
{
p = p->left;
}
n++;
}
}
//demo.c
/*************************************************************
FileName : demo.c
FileFunc : 定義實現Huffman算法
Version : V0.1
Author : Sunrier
Date : 2012-07-09 10:52:17
Descp : Linux下實現Huffman算法壓縮/解壓文件
*************************************************************/
#include <stdio.h>
#include "tree.h"
#include "queue.h"
int main(int argc,char *argv[])
{
FILE *pr,*pw;
pTree proot;
Init_TreeNode(&proot);
int num = 0;
if( argc<4 )
{
fprintf(stderr,"Usage: \n ");
fprintf(stderr," Compress : %s c sourcefile destfile \n", argv[0]);
fprintf(stderr," Decompress : %s d sourcefile destfile \n", argv[0]);
return 1;
}
if( 'c'==*argv[1] )/*表示壓縮文件*/
{
pr = fopen(argv[2],"r");
if( NULL==pr )
{
perror("Read file failed !\n");
return -1;
}
pw = fopen(argv[3],"w");
if( NULL==pw )
{
perror("Write file failed !\n");
return 1;
}
num = Read_File(proot,pr,pw);
Huffman(&proot);
fseek(pr,0,SEEK_SET);
Read_Huffman(proot,num,pr,pw);
}
else if('d'==*argv[1])/*表示解壓文件*/
{
int count,Num_Byte,ch;
pr = fopen(argv[2],"r");
if( NULL==pr )
{
perror("Read file failed !\n");
return 1;
}
fseek(pr,-12,SEEK_END);
fread(&ch,sizeof(int),1,pr);
fread(&count,sizeof(int),1,pr);
fread(&Num_Byte,sizeof(int),1,pr);
printf("%d/%d/%d\n",ch,count,Num_Byte);
fseek(pr,0,SEEK_SET);
Create_Huffman(proot,ch,pr);
Huffman(&proot);
fseek(pr,(sizeof(int)+sizeof(char))*ch,SEEK_SET);
pw = fopen(argv[3],"w");
if( NULL==pw )
{
perror("Write file failed !\n");
return 1;
}
ReHuffman(proot,pr,pw,count,Num_Byte);
}
else
{
fprintf(stderr,"Usage: \n ");
fprintf(stderr," Compress : %s c sourcefile destfile \n", argv[0]);
fprintf(stderr," Decompress : %s d sourcefile destfile \n", argv[0]);
return 1;
}
return 0;
}
//makefile
#makefile
OBJS = demo
all:$(OBJS)
#CFLAGS = -O -w -ansi
#CFLAGS = -O -Wall -ansi
CFLAGS = -g -Wall -ansi
CC = gcc $(CFLAGS)
#SRCS = *.c
SRCS = demo.c tree.c stack.c queue.c
demo:$(SRCS)
@$(CC) -o [email protected] $?
clean :
@ls | grep -v ^makefile$$ | grep -v [.]c$$ | grep -v [.]h$$ | grep -v [.]sql$$ | grep -v [.]sh$$ | xargs rm -rf
#makefile
[[email protected] Huffman]$ ls
demo.c makefile queue.c queue.h stack.c stack.h tree.c tree.h
[[email protected] Huffman]$ make
[[email protected] Huffman]$ ls
demo demo.c makefile queue.c queue.h stack.c stack.h tree.c tree.h
[[email protected] Huffman]$ ./demo c demo.c 1
……………………………
……………………………
……………………………
[[email protected] Huffman]$ ls
1 demo demo.c makefile queue.c queue.h stack.c stack.h tree.c tree.h
[[email protected] Huffman]$
[[email protected] Huffman]$ ./demo d 1 1.c
……………………………
……………………………
……………………………
[[email protected] Huffman]$ ls
1 1.c demo demo.c makefile queue.c queue.h stack.c stack.h tree.c tree.h
[[email protected] Huffman]$
注:此程序功能對於大文件的壓縮和解壓還無法實現