文本文件压缩

问题描述:采用哈夫曼编码思想实现文本文件的压缩和恢复功能。
基本要求:
(1)菜单包括:
1.录入被压缩文件名
2.压缩文件
3.恢复文件
4.验证恢复的文件是否正确
5.退出
(2)对于压缩文件功能要求:压缩前显示被压缩文件内容,然后显示对各个文本字符的哈夫曼编码,显示压缩后的结果,并保存至一个新的二进制文件中。
(3)提供恢复文件与原文件的相同性对比功能,以验证恢复的正确性。

(我是中南民族大学2019级学生,请勿抄袭,以防重复!)

#include<iostream>
#include<fstream>                   //文件读写
#include<string.h>
#include<stdio.h>
#include <windows.h>                //头文件Windows.h,可调用Windows库函数,是系统更加人性化
using namespace std;

typedef struct                                         //--------功能:保存出现字符种类的信息---------------
{
	string character;               //存放文本中的字符
	string Binary;                  //字符转化为的二进制串
	int weight;                     //字符的权值
	int parent, lchild, rchild;     //双亲,左孩子,右孩子
}HTNode, * HuffmanTree;
typedef char** HuffmanCode;
typedef struct                                          //---------功能:保存文本信息-----------------
{
    HTNode* R;                                        //对象
    int length;                                       //表长度
}MAD;
//函数定义
int CreatHTNode(MAD& L,string br[3000],char H[3000])   //统计函数,L是结构体MAD的引用,br[]从缓冲区保存文本信息,H[]是文本信息的形参
{
	string a[3000];                                    //保存文字的种类
	int y[3000];                                       //计算该文字出现的权值
	for (int j=0; j<2999; j++)
		y[j]= 1;
	char c;
	int i = 0, s = 0,r=0, x = 1, fleg;
	while ((c = H[r])!= '*')                               //将缓存区buffer数组的文本分别进行统计,直到文本最后
	{
        fleg = 0;                                          //fleg的作用是判断该字符是否在之前出现过
        br[i] = c;                                         //数组br[]存放文本内容
        for (int m = 1;m <= x;++m)                         //循环判断统计
        {
            if (a[m] == br[i])                             //如果a[]中的一个文字和缓存区的文字一直,判断相同
            {
                y[m] += 1;                                  // 出现次数加1
                fleg = 1;                                  //判读改文字已经保存在数组中
                break;
            }
        }
        if (fleg == 0)                                      //缓存区的该文字第一次出现,没有保存在数组中
        {
            a[x] = br[i];                                   //将其保存在数组中
            x++;
        }
        i++;                                                //自增实现条件循环
		r++;
	}
	int h;                                                  //x是叶子节点,2*x-1就是哈夫曼树节点总数
	h = 2 * x - 1;
	L.R = new HTNode[h + 1];
	L.length = x;                                           //
	for (int f = 1;f <= x;f++)
	{
		L.R[f].character = a[f];                            //将文本字符a[]存入结构体,character保存的值文本字符
		L.R[f].weight = y[f];                               //同理,t[]保存的是该字符串所出现的次数,警惕保存到结构体当中去
	}
	return i;                                               //函数返回int类型i,传到主函数的s,保存的是文本的长度
}
void Select(MAD&L, int len, int& s1, int& s2)               //在L中查找两个最小值,在构建哈夫曼树的时候调用
{
	int i, min1 = 0x3f3f3f3f, min2 = 0x3f3f3f3f;            //定义两个最大值min1 and min2
	for (i = 1;i <= len;i++)
	{
		if (L.R[i].weight < min1 && L.R[i].parent == 0)     //通过循环结构实现找到结构体当中权值(出现次数)最小的
		{
			min1 = L.R[i].weight;                           //将其值赋值给min1
			s1 = i;                                         //将其所处的位置传给s1
		}
	}
	int temp = L.R[s1].weight;                              //
	L.R[s1].weight = 0x3f3f3f3f;
	for (i = 1;i <= len;i++)
	{
		if (L.R[i].weight < min2 && L.R[i].parent == 0)     //与上文同理
		{
			min2 = L.R[i].weight;                            //将其权值赋值给min2,位置i传给s2
			s2 = i;
		}
	}
	L.R[s1].weight = temp;                                  //
}
void CreatHuffmanTree(MAD&L)                                //哈夫曼树插入函数,最优二叉树
{
	int n;
	n = L.length;
	int m, s1, s2, i;                                       //长度
	if (n <= 1) return;
	m = 2 * n - 1;
	for (i = 1;i <= m;++i)
	{
		L.R[i].parent = 0; L. R[i].lchild = 0;  L.R[i].rchild = 0;         //双亲左右孩子都初始化为0
	}
	for (i = n + 1;i <= m;++i)                             //
	{
		Select(L, i - 1, s1, s2);                          //调用select函数,查找最小值
		L.R[s1].parent = i;                                //建立哈夫曼树
		L.R[s2].parent = i;
		L.R[i].lchild = s1;                                //左右孩子
		L.R[i].rchild = s2;
		L.R[i].weight = L.R[s1].weight + L.R[s2].weight; 	//i 的权值为左右孩子权值之和
	}
}
void CreatHuffmanCode(MAD  L, HuffmanCode& HC)              //通过构建好的哈夫曼树,对叶子节点进行编码
{
	int i, start, c, f;                                    //
	int n;
	n = L.length;
	HC = new char* [n];
	char* cd = new char[n];
	cd[n - 1] = '\0';                                      //初始化\0,临时保存编码
	for (i = 1;i <= n;++i)
	{
		start = n - 1;
		c = i;
		f = L.R[i].parent;
		while (f != 0)                                     //根节点
		{
			--start;
			if (L.R[f].lchild == c)
				cd[start] = '0';                            //左0右1
			else
				cd[start] = '1';
			c = f;
			f = L.R[f].parent;
		}
		HC[i] = new char[n - start];
        strcpy(HC[i], &cd[start]);                           //数组H[]保存哈夫曼编码,传值给结构体
        L.R[i].Binary = HC[i];

	}
	delete cd;                                              //清除cd
}
void showHuffmanCode(MAD&L, HuffmanCode HC)            //
{
    cout<<"文字"<<"    "<<"哈夫曼编码"<<"    "<<"出现次数"<<endl;
	for (int i = 1;i <L.length;++i)                    //
	{
        cout << L.R[i].character << "       " << L.R[i].Binary << "       " << L.R[i].weight << endl;
	}
}


void Compressor(MAD& L, string b[],string o[],int s)    //文件压缩函数,将生成的哈夫曼编码通过文件读写的方式,写到写到压缩的文件中去
{
    ofstream OutFile("D:/mydesk/压缩文件.dat",ios::out);   //利用构造函数创建txt文本,并且打开该文本
	for (int q = 0;q <= s;q++)
	{
		for (int u = 0; u <= L.length - 1;u++)
		{
			if (L.R[u].character == b[q])               //
			{
				o[q] = L.R[u].Binary;
				OutFile << L.R[u].Binary;               //把字符串二进制编码内容,写入压缩包.dat文件
			}
		}
	}
	OutFile.close();                                    //关闭Test.txt文件
	cout<<"压缩成功!放置在本机桌面上!"<<endl;
}
void UnZip(MAD& L, string b[],string o[],int s)        //文件解压函数,通过保存文本信息的str[]去遍历得到相应的文字
{
    int sysm=0;
    ofstream OutFile("D:/mydesk/解压文件.txt",ios::out); //利用构造函数创建txt文本,并且打开该文本
	for (int q = 0;q <= s;q++)
	{
		for (int u = 0; u <= L.length - 1;u++)
		{
			if (L.R[u].character == b[q])              //判断条件
			{
				o[q] = L.R[u].Binary;
				sysm=1;                                 //判断解压结果与文本是否一致,不一致直接跳出循环,打印解压失败
				OutFile << L.R[u].character;           //把得到的字符写到文件中去
			}
		}
		if(sysm==0) break;
	}
	if(sysm=0) cout<<"压缩出错!"<<endl;                //判断是否压缩无误
	else cout<<"压缩结果无误"<<endl;
	OutFile.close();                                    //关闭刚才打开文件
	cout<<"解压成功!放置在本机桌面上!"<<endl;

}
int main()
{
    char fileName[20];                                  //定义一个字符数组filename[],其保存的是要经过解压操作的源文件的名称
    cout<<"输入文件名:";
    cin>>fileName;                                      //通过键盘输入
    while(1)
    {
        MAD L;int s;                                    //定义一个结构体对象
        HuffmanCode HC;                                 //
        string str[3000],o[3000];                       //str[]数组可以保存缓冲区文本信息,方便调用后面的函数
        char buffer[3000];                              //打开filename文件
        ifstream in(fileName);
        if(!in.is_open())                               //文件打开异常反馈
        {
            cout<<"Error while opening file.";
            return 1;
        }
        while(!in.eof())                                //将文件中的文本信息一一读到缓冲区buffer[]
        {
            in.getline(buffer,3000);
        }
        in.close();                                     //文件filename调用完成之后及时关闭文件
        s=CreatHTNode(L,str,buffer);                    //统计
		CreatHuffmanTree(L);                            //调用哈夫曼树构建函数,将L插入哈夫曼树当中
		CreatHuffmanCode(L, HC);                        //调用函数对哈夫曼树的叶子节点进行编码
        cout<<"------------------------------------------------欢迎使用小猿压缩程序---------------------------------------------------\n"<<endl;
        cout<<"为您提供以下使用服务:"<<endl;
        cout<<"                        1.压缩文件生成压缩包"<<endl;
        cout<<"                        2.压缩包解压"<<endl;
        cout<<"                        3.查看压缩编码"<<endl;
        cout<<"                        0.退出程序"<<endl;
        cout<<"选择序号:"<<endl;                      //菜单打印
        int number;                                    //用户通过数字,可选择调用对应函数
        cin>>number;
        switch(number)                                //switch结构
        {
                                                      //根据用户的需求,选择相对应的函数实现其功能
            case 1: system("CLS");Compressor(L,str,o,s);system("pause");break;
            case 2: system("CLS");UnZip(L,str,o,s);system("pause");break;
            case 3: system("CLS");showHuffmanCode(L, HC);system("pause");break;
            case 0 :system("CLS");cout<<"谢谢使用,祝您生活愉快!"<<endl;system("date/t");exit(0);system("pause");
            default:system("CLS");cout<<"输入有误!"<<endl;system("pause");
        }
    }
		return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

紫荆鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值