天天看點

哈夫曼編碼--------檔案壓縮與解壓

實驗目的:實作對檔案的壓縮與減壓

#include<stdio.h>
#include<stdlib.h>

#include <fstream>
using namespace std;

typedef char ElemType;
typedef struct hfmTNode
{
	ElemType element;
	int w;
	struct hfmTNode *rChild;
	struct hfmTNode *lChild;
}HFMTNode;

typedef HFMTNode hfm;

//建立隊列
typedef struct priorityQueue
{
	hfm *element;
	int n;
	int maxSize;
}PriorityQueue;

void CreatePQ(priorityQueue *PQ,int msize)
{
	PQ->maxSize=msize;
	PQ->n=0;
	PQ->element=(hfm *)malloc(msize*sizeof(hfm));
}
void AdjustUp(hfm heap[],int current)
{
	int p=current;
	hfm temp;
	while(p>0)
	{
		if(heap[p].w<heap[(p-1)/2].w)
		{
			temp=heap[p];
			heap[p]=heap[(p-1)/2];
			heap[(p-1)/2]=temp;
			p=(p-1)/2;
		}
		else
			break;
	}
}

void AdjustDown(hfm heap[],int current,int border)
{
	int p=current;
	int minchild;
	hfm temp;
	while(2*p+1<=border)
	{
		if((2*p+2<=border)&&(heap[2*p+1].w>heap[2*p+2].w))
			minchild=2*p+2;
		else
			minchild=2*p+1;
		if(heap[p].w<=heap[minchild].w)
			break;
		else
		{
			temp=heap[p];
			heap[p]=heap[minchild];
			heap[minchild]=temp;
			p=minchild;
		}
	}
}
int IsFull(PriorityQueue *PQ)
{
	if(PQ->n==PQ->maxSize)
		return 1;
	else
		return 0;
}
int IsEmpty(PriorityQueue *PQ)
{
	if(PQ->n==0)
		return 1;
	else
		return 0;
}
void Append(PriorityQueue *PQ,hfm x,int i,char *ch)
{
	if(IsFull(PQ))
		return;
	PQ->element[PQ->n]=x;
	if(i)
	{
		PQ->element[PQ->n].element=*ch;
	}
	PQ->n++;
	AdjustUp(PQ->element,PQ->n-1);
}

hfm* Serve(PriorityQueue *PQ)
{
	if(IsEmpty(PQ))
		return NULL;
	hfm *p=(hfm *)malloc(sizeof(hfm));
	p->element=PQ->element[0].element;
	p->lChild=PQ->element[0].lChild;
	p->rChild=PQ->element[0].rChild;
	p->w=PQ->element[0].w;
	PQ->n--;
	PQ->element[0]=PQ->element[PQ->n];
	AdjustDown(PQ->element,0,PQ->n-1);
	return p;
}

hfm* MakeTree(int w,hfmTNode *y,hfmTNode *z)
{
	hfm *p=(hfm *)malloc(sizeof(hfm));
	p->w=w;
	p->lChild=y;
	p->rChild=z;
	return p ;
}
//先序周遊
void PreOrder(hfm *t)
{
	if(!t)
		return;
	printf("%d  ",t->w);
	PreOrder(t->lChild);
	PreOrder(t->rChild);
}
HFMTNode* CreateHFMTree(int w[],int m)
{
	PriorityQueue PQ;
	HFMTNode *x,*y,*z;
	CreatePQ(&PQ,m);
	char ch[64];
	char c;
	c='0';
	for(int i=0;i<10;i++)
	{
		ch[i]=c+i;
	}
	c='A';
	for(int i=0;i<26;i++)
	{
		ch[i+10]=c+i;
	}
	c='a';
	for(int i=0;i<26;i++)
	{
		ch[i+36]=c+i;
	}
	ch[62]=32;
	ch[63]=10;
	for(int i=0;i<m;i++)
	{
		c=ch[i];
		x=MakeTree(w[i],NULL,NULL);
		Append(&PQ,*x,1,&c);
	}
	while(PQ.n>1)
	{
		x=Serve(&PQ);
		y=Serve(&PQ);
		if(x->w<y->w)
			z=MakeTree(x->w+y->w,x,y);
		else
		    z=MakeTree(x->w+y->w,y,x);
		
		Append(&PQ,*z,0,&c);	
	}
	return z;
}
//編碼
void CodingTree(int (*code)[100] ,int c[],char ch[],hfm *t,int *i,int j)
{
	if(!t)
		return;
	if(!t->lChild&&!t->rChild)
	{
		int p=0;
		for(int z=0;z<j;z++)
		{
			code[*i][p]=c[p];
			p++;
		}
		code[*i][p]=-1;
		ch[*i]=t->element;
		(*i)++;
		return;
	}
	else
	{
		c[j]=0;
		j++;
		CodingTree(code,c,ch,t->lChild,i,j);
	}
	
	j--;
	if(!t->lChild&&!t->rChild)
	{
		int p=0;
		for(int z=0;z<j;z++)
		{
			code[*i][p]=c[p];
			p++;
		}
		code[*i][p]=-1;
		ch[*i]=t->element;
		(*i)++;
		return;
	}
	else
	{
		c[j]=1;
		j++;
		CodingTree(code,c,ch,t->rChild,i,j);	
	}
	
}
void Coding(hfm *t,char *cc)
{
    FILE *file3;
	file3=fopen("C:/Users/123/Desktop/好好學習,天天向上/資料結構/資料/編碼檔案.txt","wb");
	if(file3==NULL)
	{
		printf("open error!\n");
		return ;
	}
    int code[100][100];
	for(int i=0;i<100;i++)
		for(int j=0;j<100;j++)
			code[i][j]=-1;
	char ch[100];
	int p=0;
	int c[100];
	for(int i=0;i<100;i++)
		c[i]=-1;
	
	//編碼
	CodingTree(code,c,ch,t,&p,0);
    int ii=0;
	unsigned char b;
	//int b[8];
	int bb=0;
	b=0;
	//int d;
	while(cc[ii]!='\0')
	{
		for(int j=0;j<p;j++)
		{
	    	if(cc[ii]==ch[j])
			{
				int pp=0;
				while(code[j][pp]!=-1)
				{
					if(bb==8)
					{
						fwrite(&b, 1, 1, file3);
						b=0;
						bb=0;
					}
					if (code[j][pp]==1)
						b = (b << 1) | 1;
				    else if(code[j][pp]==0) 
						b= b << 1;
					pp++;
					bb++;
					
				}
			}
		}
		ii++;
	}
	fclose(file3);
}

//解碼
void decode(hfm *t)
{
	FILE *file3=fopen("C:/Users/123/Desktop/好好學習,天天向上/資料結構/資料/編碼檔案.txt","rb");
	if(file3==NULL)
	{
		printf("open error!\n");
		return ;
	}
	FILE *file4=fopen("C:/Users/123/Desktop/好好學習,天天向上/資料結構/資料/編碼翻譯檔案.txt","w");
	if(file4==NULL)
	{
		printf("open error!\n");
		return ;
	}
    unsigned char la;
	long f;
	
	hfm *d;
	d=t;
    char ch=' ';
	int b=0;
	char buf[255],bx[29];
	int temp=0;
	fread(&la,1,1,file3);
		f=la;
		itoa(f, buf, 2);
		f = strlen(buf);
		for (long l = 8; l > f; l--) {
			bx[8-l]='0';
			}
		for(int i=0;i<=f;i++)
		{
			bx[i+8-f]=buf[i];
		}
	while(!feof(file3))
	{	
		if(temp==8)
		{
			fread(&la,1,1,file3);
			f=la;
			itoa(f, buf, 2);
			f = strlen(buf);
			for (long l = 8; l > f; l--) {
				bx[8-l]='0';
				}
			for(int i=0;i<=f;i++)
			{
				bx[i+8-f]=buf[i];
			}
			temp=0;
		}
		
		if(!d->lChild&&!d->rChild)
		{
			fprintf(file4,"%c",d->element);
			d=t;
			
		}
		else
		{
			
			if(bx[temp]=='0')
			{
				d=d->lChild;
			}
			if(bx[temp]=='1')
			{
				d=d->rChild;
			}
			temp++;
		}
	
	}
	fprintf(file4,"%c\n",d->element);
	fclose(file3);
	file3=NULL;
    fclose(file4);
	file4=NULL;
}	

//清空二叉樹
void Clear(hfm *t)
{
	if(!t)
		return;
	Clear(t->lChild);
	Clear(t->rChild);
	free(t);
}

//獲得權級
void frequent(char *c,int *w)
{
	char ch;
	int num[64];
	int j=0;
	for(int i=0;i<64;i++)
	{
		num[i]=0;
	}
	int n=0;
	while(c[n]!='\0')
	{
		j++;
		ch='0';
		for(int i=0;i<10;i++)
		{
			if(c[n]==ch+i)
				num[i]++;
		}
		ch='A';
		for(int i=0;i<26;i++)
		{
			if(c[n]==ch+i)
				num[i+10]++;
		}
		ch='a';
		for(int i=0;i<26;i++)
		{
			if(c[n]==ch+i)
				num[i+36]++;
		}
		if(c[n]==32)
			num[62]++;
		if(c[n]==10)
			num[63]++;
		n++;
	}
	for(int i=0;i<64;i++)
	{
		w[i]=num[i];
	}
	//向文本輸入權值
	FILE *file2=fopen("C:/Users/123/Desktop/好好學習,天天向上/資料結構/資料/權值表檔案.txt","w");
	if(file2==NULL)
	{
		printf("open error!\n");
		return ;
	}

	
	fprintf(file2,"(0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,' ','LF')\n(");
	ch='0';
	for(int i=0;i<10;i++)
	{
		fprintf(file2,"%d,",num[i]);
	}
	ch='A';
	for(int i=0;i<26;i++)
	{
		fprintf(file2,"%d,",num[i+10]);
	}
	ch='a';
	for(int i=0;i<26;i++)
	{
		fprintf(file2,"%d,",num[i+36]);
	}
	fprintf(file2,"%d,",num[62]);
	fprintf(file2,"%d)",num[63]);
	fclose(file2);
	file2=NULL;
}
//導入文本
void TEXT(int *w,char *ch)
{
	FILE *file1=fopen("C:/Users/123/Desktop/好好學習,天天向上/資料結構/資料/測試資料.txt","r");
	if(file1==NULL)
	{
		printf("open error!\n");
		return ;
	}
	char cc[300000];
	int NUM=0;
	while((cc[NUM]=fgetc(file1))!=EOF)
	{
		NUM++;
	}
	fclose(file1);
	file1=NULL;
	int num=0;
	NUM=0;
	char c;
	while(cc[NUM]!='\0')
	{
		c=cc[NUM];
	    if((48<=c&&c<=57)||(65<=c&&c<=90)||(97<=c&&c<=122)||c==10||c==32)
		{
		 	ch[num]=c;
			num++;
		}
		NUM++;
	}
	ch[num]='\0';
	frequent(ch,w);
}
void main()
{
	hfm *h;
	int w[64];
	char ch[300000];
	TEXT(w,ch);
	h=CreateHFMTree(w,64);
 	Coding(h,ch);
	decode(h);
	printf("已完成轉化\n");
	Clear(h);
}
           
  • 程式運作結果

運作前

哈夫曼編碼--------檔案壓縮與解壓
哈夫曼編碼--------檔案壓縮與解壓

運作後

權值表,編碼,和通過編碼解壓出的譯碼存在各自檔案夾中

運作後:

哈夫曼編碼--------檔案壓縮與解壓

權值表:

哈夫曼編碼--------檔案壓縮與解壓

編碼:

哈夫曼編碼--------檔案壓縮與解壓

譯碼:

哈夫曼編碼--------檔案壓縮與解壓

繼續閱讀