//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 $@ $?
- clean :
- @ls | grep -v ^makefile$$ | grep -v [.]c$$ | grep -v [.]h$$ | grep -v [.]sql$$ | grep -v [.]sh$$ | xargs rm -rf
- #makefile
[Sunrier@localhost Huffman]$ ls
demo.c makefile queue.c queue.h stack.c stack.h tree.c tree.h
[Sunrier@localhost Huffman]$ make
[Sunrier@localhost Huffman]$ ls
demo demo.c makefile queue.c queue.h stack.c stack.h tree.c tree.h
[Sunrier@localhost Huffman]$ ./demo c demo.c 1
.................................
.................................
.................................
[Sunrier@localhost Huffman]$ ls
1 demo demo.c makefile queue.c queue.h stack.c stack.h tree.c tree.h
[Sunrier@localhost Huffman]$
[Sunrier@localhost Huffman]$ ./demo d 1 1.c
.................................
.................................
.................................
[Sunrier@localhost Huffman]$ ls
1 1.c demo demo.c makefile queue.c queue.h stack.c stack.h tree.c tree.h
[Sunrier@localhost Huffman]$
注:此程序功能对于大文件的压缩和解压还无法实现