2019程序设计与算法训练实验报告存档

哈夫曼树压缩
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>//求文件大小的库函数 
// 统计字符频度的临时结点
typedef struct {
	unsigned char uch;			// 以8bits为单元的无符号字符
	unsigned long weight;		// 每类(以二进制编码区分)字符出现频度
	int flag;                   //交互输入时判断是否已存在 
} TmpNode;
// 哈夫曼树结点
typedef struct {
	unsigned char uch;				// 以8bits为单元的无符号字符
	unsigned long weight;			// 每类(以二进制编码区分)字符出现频度
	char *code;						// 字符对应的哈夫曼编码(动态分配存储空间)
	int parent, lchild, rchild;		// 定义双亲和左右孩子
} HufNode, *HufTree;
typedef char elementType;
typedef struct lBnode
{
	elementType data;
	struct lBnode *lChild,*rChild;
 } BiNode,*BiTree;//二叉链表结构
// 选择最小和次小的两个结点,建立哈夫曼树调用
void select(HufNode *huf_tree, unsigned int n, int *s1, int *s2)
{
	// 找最小权值的结点 
	unsigned int i;
	unsigned long min = ULONG_MAX;
	*s1=*s2=0;
	for(i = 0; i < n; ++i)           
		if(huf_tree[i].parent == 0 && huf_tree[i].weight < min)
		{
			min = huf_tree[i].weight;
			*s1 = i;
		}
		huf_tree[*s1].parent=1;   // 标记此结点已被选中
	// 找次小
	min=ULONG_MAX;
	for(i = 0; i < n; ++i)            
		if(huf_tree[i].parent == 0 && huf_tree[i].weight < min)
		{
			min = huf_tree[i].weight;
			*s2 = i;
		}
} 
// 建立哈夫曼树
void CreateTree(HufNode *huf_tree, unsigned int char_kinds, unsigned int node_num)
{
	unsigned int i;
	int s1, s2;
	for(i = char_kinds; i < node_num; ++i)  
	{ 
		select(huf_tree, i, &s1, &s2);		// 选择最小的两个结点
		huf_tree[s1].parent = huf_tree[s2].parent = i; 
		huf_tree[i].lchild = s1; 
		huf_tree[i].rchild = s2; //建立联系 
		huf_tree[i].weight = huf_tree[s1].weight + huf_tree[s2].weight; 
	} 
}
//打印哈夫曼树
int printTree(char *ifname,char *ofname) 
{
	unsigned int i, j;
	unsigned int char_kinds;		// 字符种类
	unsigned char char_temp;		// 暂存8bits字符
	unsigned long file_len = 0;
	FILE *infile, *outfile;
	TmpNode node_temp;
	unsigned int node_num;
	HufTree huf_tree;
	char code_buf[256] = "\0";		// 待存编码缓冲区
	unsigned int code_len;
	TmpNode *tmp_nodes =(TmpNode *)malloc(256*sizeof(TmpNode));		
	// 初始化暂存结点
	for(i = 0; i < 256; ++i)
	{
		tmp_nodes[i].weight = 0;
		tmp_nodes[i].uch = (unsigned char)i;		// 数组的256个下标与256种字符对应
	}
	// 遍历文件,获取字符频度
	infile = fopen(ifname, "rb");
	// 判断输入文件是否存在
	if (infile == NULL)
		return -1;
	fread((char *)&char_temp, sizeof(unsigned char), 1, infile);		// 读入一个字符
	while(!feof(infile))
	{
		++tmp_nodes[char_temp].weight;		// 统计下标对应字符的权重,利用数组的随机访问快速统计字符频度
		++file_len;
		fread((char *)&char_temp, sizeof(unsigned char), 1, infile);		// 读入一个字符
	}
	fclose(infile);
	// 排序,将频度为零的放最后,剔除
	for(i = 0; i < 256-1; ++i)           
		for(j = i+1; j < 256; ++j)
			if(tmp_nodes[i].weight < tmp_nodes[j].weight)
			{
				node_temp = tmp_nodes[i];
				tmp_nodes[i] = tmp_nodes[j];
				tmp_nodes[j] = node_temp;
			}//冒泡排序 
	// 统计实际的字符种类(出现次数不为0)
	for(i = 0; i < 256; ++i)
		if(tmp_nodes[i].weight == 0) 
			break;
	char_kinds = i;
	if (char_kinds == 1)
	{
		outfile = fopen(ofname, "wb");					// 打开压缩后将生成的文件
		fwrite((char *)&char_kinds, sizeof(unsigned int), 1, outfile);		// 写入字符种类
		fwrite((char *)&tmp_nodes[0].uch, sizeof(unsigned char), 1, outfile);		// 写入唯一的字符
		fwrite((char *)&tmp_nodes[0].weight, sizeof(unsigned long), 1, outfile);		// 写入字符频度,也就是文件长度
		free(tmp_nodes);
		fclose(outfile);
	}
	else
	{
		node_num = 2 * char_kinds - 1;		// 根据字符种类数,计算建立哈夫曼树所需结点数 
		huf_tree = (HufNode *)malloc(node_num*sizeof(HufNode));		// 动态建立哈夫曼树所需结点     
		// 初始化前char_kinds个结点
		for(i = 0; i < char_kinds; ++i) 
		{ 
			// 将暂存结点的字符和频度拷贝到树结点
			huf_tree[i].uch = tmp_nodes[i].uch; 
			huf_tree[i].weight = tmp_nodes[i].weight;
			huf_tree[i].parent = 0; 
			huf_tree[i].lchild = 0;
			huf_tree[i].rchild = 0; //初始化节点的父节点、左孩子、右孩子 
		}	
		free(tmp_nodes); // 释放字符频度统计的暂存区
		// 初始化后node_num-char_kins个结点
		for(; i < node_num; ++i) 
		{
			huf_tree[i].parent = 0;
			huf_tree[i].lchild = 0;
			huf_tree[i].rchild = 0; 
		}
		CreateTree(huf_tree, char_kinds, node_num);		// 创建哈夫曼树
        printf("下标   元素    父节点  \n");
		for(i=1;i<char_kinds;i++)
		{
			printf("%2d ",i);
			printf("%6c     ",huf_tree[i].uch);
			printf("%8d     \n",huf_tree[i].parent); 	//打印每个结点的下标、对应的符号、父节点下标 
		}
	    // 关闭文件
		fclose(infile);
		fclose(outfile);
		// 释放内存
		for(i = 0; i < char_kinds; ++i)
			free(huf_tree[i].code);
		free(huf_tree);
    }
}
// 生成哈夫曼编码
void HufCode(HufNode *huf_tree, unsigned char_kinds)
{
	unsigned int i;
	int cur, next, index;
	char *code_tmp = (char *)malloc(256*sizeof(char));		// 暂存编码,最多256个叶子,编码长度不超多255
	code_tmp[256-1] = '\0'; 
	for(i = 0; i < char_kinds; ++i) 
	{
		index = 256-1;	// 编码临时空间索引初始化
		// 从叶子向根反向遍历求编码
		for(cur = i, next = huf_tree[i].parent; next != 0; 
			cur = next, next = huf_tree[next].parent)  
			if(huf_tree[next].lchild == cur) 
				code_tmp[--index] = '0';	// 左孩子是0
			else 
				code_tmp[--index] = '1';	// 右孩子是1
		huf_tree[i].code = (char *)malloc((256-index)*sizeof(char));		
		strcpy(huf_tree[i].code, &code_tmp[index]);     // 保存哈夫曼编码到树结点中
	} 
	free(code_tmp);		// 释放编码临时空间
}
// 压缩函数
int compress(char *ifname, char *ofname)
{
	unsigned int i, j;
	unsigned int c_kinds;		// 字符种类
	unsigned char c_temp;		// 暂存8bits字符
	unsigned long file_len = 0;
	FILE *infile, *outfile;
	TmpNode node_temp;
	unsigned int node_num;
	HufTree huf_tree;
	char code_buf[256] = "\0";		// 待存编码缓冲区
	unsigned int code_len;
	TmpNode *tmp_nodes =(TmpNode *)malloc(256*sizeof(TmpNode));		
	// 初始化暂存结点
	for(i = 0; i < 256; ++i)
	{
		tmp_nodes[i].weight = 0;
		tmp_nodes[i].uch = (unsigned char)i;		// 数组的256个下标与256种字符对应
	}
	// 遍历文件,获取字符频度
	infile = fopen(ifname, "rb");
	// 判断输入文件是否存在
	if (infile == NULL)
		return -1;
	fread((char *)&c_temp, sizeof(unsigned char), 1, infile);		// 读入一个字符
	while(!feof(infile))
	{
		++tmp_nodes[c_temp].weight;		// 统计下标对应字符的权重,利用数组的随机访问快速统计字符频度
		++file_len;
		fread((char *)&c_temp, sizeof(unsigned char), 1, infile);		// 读入一个字符
	}
	fclose(infile);
	//冒泡 排序,将频度为零的放最后,剔除
	for(i = 0; i < 256-1; ++i)           
		for(j = i+1; j < 256; ++j)
			if(tmp_nodes[i].weight < tmp_nodes[j].weight)
			{
				node_temp = tmp_nodes[i];
				tmp_nodes[i] = tmp_nodes[j];
				tmp_nodes[j] = node_temp;
			}
	// 统计实际的字符种类(出现次数不为0)
	for(i = 0; i < 256; ++i)
		if(tmp_nodes[i].weight == 0) 
			break;
	c_kinds = i;
	//只有一个字符的情况单独考虑 
	if(c_kinds != 1)
	{
		node_num = 2 * c_kinds - 1;		// 根据字符种类数,计算建立哈夫曼树所需结点数 
		huf_tree = (HufNode *)malloc(node_num*sizeof(HufNode));		// 动态建立哈夫曼树所需结点     
		// 初始化前char_kinds个结点
		for(i = 0; i < c_kinds; ++i) 
		{ 
			// 将暂存结点的字符和频度拷贝到树结点
			huf_tree[i].uch = tmp_nodes[i].uch; 
			huf_tree[i].weight = tmp_nodes[i].weight;
			huf_tree[i].parent = 0; 
		}	
		free(tmp_nodes); // 释放字符频度统计的暂存区
		// 初始化后node_num-char_kins个结点
		for(; i < node_num; ++i) 
			huf_tree[i].parent = 0; 

		CreateTree(huf_tree, c_kinds, node_num);		// 创建哈夫曼树
		HufCode(huf_tree, c_kinds);		// 生成哈夫曼编码
		// 写入字符和相应权重,供解压时重建哈夫曼树
		outfile = fopen(ofname, "wb");					// 打开压缩后将生成的文件
		fwrite((char *)&c_kinds, sizeof(unsigned int), 1, outfile);		// 写入字符种类
		for(i = 0; i < c_kinds; ++i)
		{
			fwrite((char *)&huf_tree[i].uch, sizeof(unsigned char), 1, outfile);			// 写入字符(已排序,读出后顺序不变)
			fwrite((char *)&huf_tree[i].weight, sizeof(unsigned long), 1, outfile);		// 写入字符对应权重
		}
		// 紧接着字符和权重信息后面写入文件长度和字符编码
		fwrite((char *)&file_len, sizeof(unsigned long), 1, outfile);		// 写入文件长度
		infile = fopen(ifname, "rb");		// 以二进制形式打开待压缩的文件
		fread((char *)&c_temp, sizeof(unsigned char), 1, infile);     // 每次读取8bits
		while(!feof(infile))
		{
			// 匹配字符对应编码
			for(i = 0; i < c_kinds; ++i)
				if(c_temp == huf_tree[i].uch)
					strcat(code_buf, huf_tree[i].code);
			// 以8位(一个字节长度)为处理单元
			while(strlen(code_buf) >= 8)
			{
				c_temp = '\0';		// 清空字符暂存空间,改为暂存字符对应编码
				for(i = 0; i < 8; ++i)
				{
					c_temp <<= 1;		// 左移一位,为下一个bit腾出位置
					if(code_buf[i] == '1')
						c_temp |= 1;		// 当编码为"1",通过或操作符将其添加到字节的最低位
				}
				fwrite((char *)&c_temp, sizeof(unsigned char), 1, outfile);		// 将字节对应编码存入文件
				strcpy(code_buf, code_buf+8);		// 编码缓存去除已处理的前八位
			}
			fread((char *)&c_temp, sizeof(unsigned char), 1, infile);     // 每次读取8bits
		}
		// 处理最后不足8bits编码
		code_len = strlen(code_buf);
		if(code_len > 0)
		{
			c_temp = '\0';		
			for(i = 0; i < code_len; ++i)
			{
				c_temp <<= 1;		
				if(code_buf[i] == '1')
					c_temp |= 1;
			}
			c_temp <<= 8-code_len;       // 将编码字段从尾部移到字节的高位
			fwrite((char *)&c_temp, sizeof(unsigned char), 1, outfile);       // 存入最后一个字节
		}
		// 关闭文件
		fclose(infile);
		fclose(outfile);
		// 释放内存
		for(i = 0; i < c_kinds; ++i)
			free(huf_tree[i].code);
		free(huf_tree);
	}
	else
	{
		outfile = fopen(ofname, "wb");					// 打开压缩后将生成的文件
		fwrite((char *)&c_kinds, sizeof(unsigned int), 1, outfile);		// 写入字符种类
		fwrite((char *)&tmp_nodes[0].uch, sizeof(unsigned char), 1, outfile);		// 写入唯一的字符
		fwrite((char *)&tmp_nodes[0].weight, sizeof(unsigned long), 1, outfile);		// 写入字符频度,也就是文件长度
		free(tmp_nodes);
		fclose(outfile);
	}
}
// 解压函数
int extract(char *ifname, char *ofname)
{
	unsigned int i;
	unsigned long file_len;
	unsigned long writen_len = 0;		// 控制文件写入长度
	FILE *infile, *outfile;
	unsigned int char_kinds;		// 存储字符种类
	unsigned int node_num;
	HufTree huf_tree;
	unsigned char code_temp;		// 暂存8bits编码
	unsigned int root;		// 保存根节点索引,供匹配编码使用
	infile = fopen(ifname, "rb");		// 以二进制方式打开压缩文件
	// 判断输入文件是否存在
	if (infile == NULL)
		return -1;
	// 读取压缩文件前端的字符及对应编码,用于重建哈夫曼树
	fread((char *)&char_kinds, sizeof(unsigned int), 1, infile);     // 读取字符种类数
	if (char_kinds == 1)
	{
		fread((char *)&code_temp, sizeof(unsigned char), 1, infile);     // 读取唯一的字符
		fread((char *)&file_len, sizeof(unsigned long), 1, infile);     // 读取文件长度
		outfile = fopen(ofname, "wb");					// 打开压缩后将生成的文件
		while (file_len--)
		{
			fwrite((char *)&code_temp, sizeof(unsigned char), 1, outfile);
		}
				
		fclose(infile);
		fclose(outfile);
	}
	else
	{
		node_num = 2 * char_kinds - 1;		// 根据字符种类数,计算建立哈夫曼树所需结点数 
		huf_tree = (HufNode *)malloc(node_num*sizeof(HufNode));		// 动态分配哈夫曼树结点空间
		// 读取字符及对应权重,存入哈夫曼树节点
		for(i = 0; i < char_kinds; ++i)     
		{
			fread((char *)&huf_tree[i].uch, sizeof(unsigned char), 1, infile);		// 读入字符
			fread((char *)&huf_tree[i].weight, sizeof(unsigned long), 1, infile);	// 读入字符对应权重
			huf_tree[i].parent = 0;
		}
		// 初始化后node_num-char_kins个结点的parent
		for(1; i < node_num; ++i) 
			huf_tree[i].parent = 0;
		CreateTree(huf_tree, char_kinds, node_num);		// 重建哈夫曼树(与压缩时的一致)
		// 读完字符和权重信息,读取文件长度和编码,进行解码
		fread((char *)&file_len, sizeof(unsigned long), 1, infile);	// 读入文件长度
		outfile = fopen(ofname, "wb");		// 打开压缩后将生成的文件
		root = node_num-1;
		//计算出根节点编号 
		while(1)
		{
			fread((char *)&code_temp, sizeof(unsigned char), 1, infile);		// 读取一个字符长度的编码
			// 处理读取的一个字符长度的编码(通常为8位)
			for(i = 0; i < 8; ++i)
			{
				// 由根向下直至叶节点正向匹配编码对应字符
				if(code_temp & 128)
				{
					root = huf_tree[root].rchild;	
		    	}
				
				else
				{
					root = huf_tree[root].lchild;
				}
					
				if(root < char_kinds)
				{
					fwrite((char *)&huf_tree[root].uch, sizeof(unsigned char), 1, outfile);
					++writen_len;
					if (writen_len == file_len)
					{
						break;
					 } 
						// 控制文件长度,跳出内层循环
					root = node_num-1;        // 复位为根索引,匹配下一个字符
				}
				code_temp <<= 1;		// 将编码缓存的下一位移到最高位,供匹配
			}
			if (writen_len == file_len) 
			{
			    break;		// 控制文件长度,跳出外层循环
	    	}
		
		fclose(infile);
		fclose(outfile);
		//关闭文件 
		// 释放内存
		free(huf_tree);
	}
}
}
//打印哈夫曼编码表
int printcode(char *ifname ,char *ofname)
{
	unsigned int i, j;
	unsigned int char_kinds;		// 字符种类
	unsigned char char_temp;		// 暂存8bits字符
	unsigned long file_len = 0;
	FILE *infile, *outfile;
	TmpNode node_temp;
	unsigned int node_num;
	HufTree huf_tree;
	char code_buf[256] = "\0";		// 待存编码缓冲区
	unsigned int code_len;
	TmpNode *t_nodes =(TmpNode *)malloc(256*sizeof(TmpNode));		
	// 初始化暂存结点
	for(i = 0; i < 256; ++i)
	{
		t_nodes[i].weight = 0;
		t_nodes[i].uch = (unsigned char)i;		// 数组的256个下标与256种字符对应
	}
	// 遍历文件,获取字符频度
	infile = fopen(ifname, "rb");
	// 判断输入文件是否存在
	if (infile == NULL)
	{
		return -1;	//-1代表文件打开失败或不存在 
	} 
	
	fread((char *)&char_temp, sizeof(unsigned char), 1, infile);		// 读入一个字符
	while(!feof(infile))
	{
		++t_nodes[char_temp].weight;		// 统计下标对应字符的权重,利用数组的随机访问快速统计字符频度
		++file_len;
		fread((char *)&char_temp, sizeof(unsigned char), 1, infile);		// 读入一个字符
	}
	fclose(infile);
	//关闭文件 
	// 排序,将频度为零的放最后,剔除
	for(i = 0; i < 256-1; ++i)   
	{
		for(j = i+1; j < 256; ++j)
		{
			if(t_nodes[i].weight < t_nodes[j].weight)
			{
				node_temp = t_nodes[i];
				t_nodes[i] = t_nodes[j];
				t_nodes[j] = node_temp;
			}
		}	
	}        //冒泡排序 
	// 统计实际的字符种类(出现次数不为0)
	for(i = 0; i < 256; ++i)
		if(t_nodes[i].weight == 0) 
			break;
	char_kinds = i;
	if (char_kinds == 1)
	{
		outfile = fopen(ofname, "wb");					// 打开压缩后将生成的文件
		fwrite((char *)&char_kinds, sizeof(unsigned int), 1, outfile);		// 写入字符种类
		fwrite((char *)&t_nodes[0].uch, sizeof(unsigned char), 1, outfile);		// 写入唯一的字符
		fwrite((char *)&t_nodes[0].weight, sizeof(unsigned long), 1, outfile);		// 写入字符频度,也就是文件长度
		free(t_nodes);//释放内存 
		fclose(outfile);//关闭文件 
	}
	else
	{
		node_num = 2 * char_kinds - 1;		// 根据字符种类数,计算建立哈夫曼树所需结点数 
		huf_tree = (HufNode *)malloc(node_num*sizeof(HufNode));		// 动态建立哈夫曼树所需结点     
		// 初始化前char_kinds个结点
		for(i = 0; i < char_kinds; ++i) 
		{ 
			// 将暂存结点的字符和频度拷贝到树结点
			huf_tree[i].uch = t_nodes[i].uch; 
			huf_tree[i].weight = t_nodes[i].weight;
			huf_tree[i].parent = 0; 
		}	
		free(t_nodes); // 释放字符频度统计的暂存区
		// 初始化后node_num-char_kins个结点
		for(; i < node_num; ++i) 
		{
			huf_tree[i].parent = 0; 
		} 
		//初始化结点的父节点	
		CreateTree(huf_tree, char_kinds, node_num);		// 创建哈夫曼树
		HufCode(huf_tree, char_kinds);		// 生成哈夫曼编码
		for(i=0;i<node_num;i++)
		{
			printf("%c    %s\n",huf_tree[i].uch,huf_tree[i].code);
		}	
		// 关闭文件
		fclose(infile);
		fclose(outfile);
		// 释放内存
		for(i = 0; i < char_kinds; ++i)
			free(huf_tree[i].code);
		free(huf_tree);
    }
 } 
 //WPL
 int length(char str[])
 {
 	int i,len=0;
 	for(i=0;str[i]!='\0';i++)
 	{
 		len++;
	 }
	 return len-1;
 }
 //求出每个结点的哈夫曼编码,编码的长度就是这个节点位于哈夫曼树的第几层 
 int wpl(char *ifname ,char *ofname)
 {
 	int p,a,b;
 	a=b=1;
 	unsigned int i, j;
	unsigned int char_kinds;		// 字符种类
	unsigned char char_temp;		// 暂存8bits字符
	unsigned long file_len = 0;
	FILE *infile, *outfile;
	TmpNode node_temp;
	unsigned int node_num;
	HufTree huf_tree;
	char code_buf[256] = "\0";		// 待存编码缓冲区
	unsigned int code_len;
	/*
	** 动态分配256个结点,暂存字符频度,
	** 统计并拷贝到树结点后立即释放
	*/
	TmpNode *tmp_nodes =(TmpNode *)malloc(256*sizeof(TmpNode));		
	// 初始化暂存结点
	for(i = 0; i < 256; ++i)
	{
		tmp_nodes[i].weight = 0;
		tmp_nodes[i].uch = (unsigned char)i;		// 数组的256个下标与256种字符对应
	}
	// 遍历文件,获取字符频度
	infile = fopen(ifname, "rb");
	// 判断输入文件是否存在
	if (infile == NULL)
		return -1;
	fread((char *)&char_temp, sizeof(unsigned char), 1, infile);		// 读入一个字符
	while(!feof(infile))
	{
		++tmp_nodes[char_temp].weight;		// 统计下标对应字符的权重,利用数组的随机访问快速统计字符频度
		++file_len;
		fread((char *)&char_temp, sizeof(unsigned char), 1, infile);		// 读入一个字符
	}
	fclose(infile);
	// 排序,将频度为零的放最后,剔除
	for(i = 0; i < 256-1; ++i)           
		for(j = i+1; j < 256; ++j)
			if(tmp_nodes[i].weight < tmp_nodes[j].weight)
			{
				node_temp = tmp_nodes[i];
				tmp_nodes[i] = tmp_nodes[j];
				tmp_nodes[j] = node_temp;
			}
	// 统计实际的字符种类(出现次数不为0)
	for(i = 0; i < 256; ++i)
		if(tmp_nodes[i].weight == 0) 
			break;
	char_kinds = i;
	if (char_kinds == 1)
	{
		outfile = fopen(ofname, "wb");					// 打开压缩后将生成的文件
		fwrite((char *)&char_kinds, sizeof(unsigned int), 1, outfile);		// 写入字符种类
		fwrite((char *)&tmp_nodes[0].uch, sizeof(unsigned char), 1, outfile);		// 写入唯一的字符
		fwrite((char *)&tmp_nodes[0].weight, sizeof(unsigned long), 1, outfile);		// 写入字符频度,也就是文件长度
		free(tmp_nodes);
		fclose(outfile);
	}
	else
	{
		node_num = 2 * char_kinds - 1;		// 根据字符种类数,计算建立哈夫曼树所需结点数 
		huf_tree = (HufNode *)malloc(node_num*sizeof(HufNode));		// 动态建立哈夫曼树所需结点     
		// 初始化前char_kinds个结点
		for(i = 0; i < char_kinds; ++i) 
		{ 
			// 将暂存结点的字符和频度拷贝到树结点
			huf_tree[i].uch = tmp_nodes[i].uch; 
			huf_tree[i].weight = tmp_nodes[i].weight;
			huf_tree[i].parent = 0; 
		}	
		free(tmp_nodes); // 释放字符频度统计的暂存区
		// 初始化后node_num-char_kins个结点
		for(; i < node_num; ++i) 
			huf_tree[i].parent = 0; 
		CreateTree(huf_tree, char_kinds, node_num);		// 创建哈夫曼树
    	HufCode(huf_tree, char_kinds);		// 生成哈夫曼编码
    	//因为是动态分配内存所以每一步都需要重新压缩,生成哈夫曼编码 
		int mix=0,temp;
	    for(i=0;i<=83;i++)
	    {
	    	a=(int)huf_tree[i].weight;
	    	b=length(huf_tree[i].code);
	    	a=a*b;
	    	mix=mix+a;
	        if(i==83)
	        {
	        	printf(" WPL = %d\n",mix);	//求出WPL 
		    }
		}
		return 0;	
    } 
 }
//求文件大小 
//调用了sys/stat.h头文件来求文件大小 
int file_size(char* filename)//获取文件名为filename的文件大小。
{
    struct stat statbuf;
    int r;
    r = stat(filename,&statbuf);//调用stat函数
    if(r != 0) return -1;//获取失败。
    return statbuf.st_size;//返回文件大小。
}
int main()
{
	while(1)
	{
		int opt, flag  = 0;		// 每次进入循环都要初始化flag为0
		char ifname[256], ofname[256];		// 保存输入输出文件名
		int *w1;
		int size1=0;//源文件大小 
		int size2=0;//压缩文件大小 
		float ratio=0;//压缩比 
		printf("---------------------------------------------------------------------------\n") ;
		printf("  Please input the number of operations: \n") ;
		printf("  1: compress\n") ;
		printf("  2: extract\n") ;
		printf("  3: Print \n") ;
		printf("  4: WPL\n") ;
		printf("  5: hufcode\n") ;
		printf("  6: compression ratio\n") ;
		printf("  7: quit\n") ;
		printf("---------------------------------------------------------------------------\n") ;	
		scanf("%d", &opt);
		if (opt == 7)
			break;
		switch(opt)
		{
		case 1: 
		    printf("Please input the infile name: ");
			fflush(stdin);		// 清空标准输入流,防止干扰gets函数读取文件名
			gets(ifname);
			printf("Please input the outfile name: ");
			fflush(stdin);
			gets(ofname); 
		    printf("Compressing……\n");
			flag = compress(ifname, ofname);	// 压缩,返回值用于判断是否文件名不存在
			break;		
		case 2: 
		    printf("Please input the infile name: ");
			fflush(stdin);		// 清空标准输入流,防止干扰gets函数读取文件名
			gets(ifname);
			printf("Please input the outfile name: ");
			fflush(stdin);
			gets(ofname); 
		    printf("Extracting……\n");
			flag = extract(ifname, ofname);		// 解压,返回值用于判断是否文件名不存在
			break;
		case 3:
		    printf("Please input the infile name: ");
			fflush(stdin);		// 清空标准输入流,防止干扰gets函数读取文件名
			gets(ifname);
			printf("Please input the outfile name: ");
			fflush(stdin);
			gets(ofname); 
			flag = compress(ifname, ofname);	// 压缩,返回值用于判断是否文件名不存在
			printTree(ifname,ofname) ;//打印哈夫曼树 
			break;
		case 4:	
		    printf("Please input the infile name: ");
			fflush(stdin);		// 清空标准输入流,防止干扰gets函数读取文件名
			gets(ifname);
			printf("Please input the outfile name: ");
			fflush(stdin);
			gets(ofname); 
			flag = compress(ifname, ofname);	// 压缩,返回值用于判断是否文件名不存在
		    wpl(ifname,ofname);//求WPL 
		    break;
		case 5:
			printf("Please input the infile name: ");
			fflush(stdin);		// 清空标准输入流,防止干扰gets函数读取文件名
			gets(ifname);
			printf("Please input the outfile name: ");
			fflush(stdin);
			gets(ofname); 
			flag = compress(ifname, ofname);	// 压缩,返回值用于判断是否文件名不存在
			printcode(ifname,ofname);//打印哈夫曼编码 
			break;	
		case 6:
			printf("Please input the infile name: ");
			fflush(stdin);		// 清空标准输入流,防止干扰gets函数读取文件名
			gets(ifname);
			printf("Please input the outfile name: ");
			fflush(stdin);
			gets(ofname); 
			flag = compress(ifname, ofname);	// 压缩,返回值用于判断是否文件名不存在
			size1=file_size(ifname);//求原文件大小 
			printf("Source file size = %d\n",size1);
			size2=file_size(ofname);//求压缩后文件大小 
			printf("Compressed flie size = %d\n",size2);
			ratio=(float)size2/(float)size1;//压缩比
			printf("the compress ratio is %f\n",ratio);	
			break;
		}
		if (flag == -1)
		{
			printf("Sorry, infile \"%s\" doesn't exist!\n", ifname);
		 } 
			// 如果标志为-1则输入文件不存在
		else
		{
			printf("Operation is done!\n");
		}
			// 操作完成
	}
	return 0;
}
发布了7 篇原创文章 · 获赞 0 · 访问量 42

猜你喜欢

转载自blog.csdn.net/Hireath_/article/details/104572275