哈夫曼编码--------文件压缩与解压

实验目的:实现对文件的压缩与减压

#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);
}
  • 程序运行结果

运行前
在这里插入图片描述
在这里插入图片描述

运行后
权值表,编码,和通过编码解压出的译码存在各自文件夹中

运行后:
在这里插入图片描述

权值表:
在这里插入图片描述
编码:
在这里插入图片描述

译码:
在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值