哈夫曼压缩算法与解压

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cx1165597739/article/details/80685449

算法思路如下:压缩:这个实验一开始将文件中的字符串读取到一个vector中,然后通过处理vector中的字符,建立了n个节点,每个节点包括每个字符和出现的频率,然后建立2*n个哈夫曼节点,前n个哈夫曼节点和节点的内容相同,后面的n个节点是用于构建哈夫曼树的非叶节点,然后构建哈夫曼树,把这些节点连接起来,生成哈夫曼树,生成哈夫曼编码时,从叶节点开始时逐步向根节点延申,获得哈夫曼编码,将编码输出到compression.txt中可以看到具体的哈夫曼编码,同时将编码输出到二进制文件compression_2.dat中,然后用一个map(string,char)来存储哈夫曼编码,string为编码,char为字符。

解压:通过从compression_2.dat文件中读取01串,存到string中,与map中的键值进行比较,如果相等,就把map的值输出带decompression中,如果不相等,继续读取01字符。直到读取结束。

代码如下:

#include <iostream>
#include <Windows.h>
#include <fstream>
#include <vector>
#include<stdio.h>
#include <algorithm>
#include <cstring>
#include <map> 
#include <bitset>
using namespace std;
typedef struct
{
	int weight;
	int parent, lchild, rchild;
}HafuNode,*HufumanTree;
typedef struct
{
	char *data;
	int *num;
	int length;
}TNode;
typedef struct
{
	char *data;
	char** HM;
}Code;
typedef char** HuffmanCode;
void initTnode(TNode &tnod)
{
	tnod.data = new char[256];
	tnod.num = new int[256];
	if (tnod.data == NULL || tnod.num==NULL)
	{
		cout << "发生错误" << endl;
		exit(1);
	}
	tnod.length = 0;
}
void initmap(map<string, char>& hafuman, HuffmanCode code, int n,TNode node,int &codelength)
{
	for (int i = 1; i <= n; i++)
	{
		string s = code[i];
		hafuman.insert(pair<string, char>(s, node.data[i - 1]));
		codelength = s.size()*node.num[i - 1]+ codelength;
	}

		
}
void Read(vector<char>& s)
{
	char ch;
	ifstream infile("test.txt", ios::in);
	if (!infile)
	{
		cout << "open error" << endl;
		exit(1);
	}
	while (infile.peek() != EOF)
	{
		 infile.get(ch);
		 s.push_back(ch);
	}
	infile.close();
}
bool find(const char ch, TNode t)
{
	for (int i = 0; i < t.length; i++)
	{
		if (t.data[i] == ch)
		{
			return true;
		}
	}
	return false;
}
void TNodeCount(TNode &t, vector<char> v)
{
	int m = v.size(),j=0;
	char ch;
	for (int i = 0; i < m; i++)
	{
		ch = v[i];
		if (!find(ch, t))
		{
			t.data[j] = ch;
			t.num[j] = count(v.begin(), v.end(), ch);
			t.length++;
			j++;
		}
	}
}
void Select(HufumanTree &tree, int a, int &b, int &c)
{
	int min1, min2, minweight = 10000;
	for (int i = 1; i <= a; i++)
	{
		if (tree[i].parent == 0)
		{
			if (tree[i].weight < minweight)
			{
				minweight = tree[i].weight;
				min1 = i;
			}
		}
	}
	tree[min1].parent = 1;
	minweight = 10000;
	for (int i = 1; i <= a; i++)
	{
		if (tree[i].parent == 0)
		{
			if (tree[i].weight < minweight)
			{
				minweight = tree[i].weight;
				min2 = i;
			}
		}
	}
	tree[min2].parent = 1;
	b = min1;
	c = min2;
}
void CreateHuffmanTree(HufumanTree &tree, TNode node, int n)
{
	if (n <= 1)
	{
		return;
	}
	int m = 2 * n - 1;
	tree = new HafuNode[m+1];
	for (int i = 1; i <= m; i++)//为0表示没有左右节点,父节点
	{
		tree[i].lchild = 0;
		tree[i].parent = 0;
		tree[i].rchild = 0;
	}
	for (int i = 1; i <= n; i++)
	{
		tree[i].weight = node.num[i - 1];
	}
	int s1, s2;
	for (int i = n + 1; i <= m; i++)
	{
		Select(tree, i - 1, s1, s2);
		tree[s1].parent = i;
		tree[s2].parent = i;
		tree[i].lchild = s1;
		tree[i].rchild = s2;
		tree[i].weight = tree[s1].weight + tree[s2].weight;
	}
}
void CreatHuffmanCode(HufumanTree tree, HuffmanCode &code, int n)
{
	int pare, child, start;
	code = new char *[n + 1];
	char* cd = new char[n];
	cd[n - 1] = '\0';
	for (int i = 1; i <= n; i++)
	{
		start = n - 1;
		child = i;
		pare = tree[i].parent;
		while (pare != 0)
		{
			start--;
			if (child == tree[pare].lchild)
			{
				cd[start] = '0';
			}
			else
			{
				cd[start] = '1';
			}
			child = pare;
			pare = tree[child].parent;
		}
		code[i] = new char[n - start];
		strcpy(code[i], &cd[start]);
	}
	delete cd ;
}
void compression(HuffmanCode code,vector<char> v, TNode node)
{
	int i, j, k;
	ofstream outfile("compression.txt", ios::out);
	if (!outfile)
	{
		cerr << "open error" << endl;
		exit(1);
	}
	for ( i = 0; i < v.size(); i++)
	{
		for ( j = 0; j < node.length; j++)
		{
			if(node.data[j] == v[i])
			{
				break;
			}
		}
		for (k = 0; code[j+1][k] != '\0'; k++)
		{
			outfile << code[j+1][k];
		}
	}
	outfile.close();
	cout << "压缩成功!,可以到compression.txt中查看" << endl;
	Sleep(500);
}
void decompression(map<string, char> hafuman,int length)
{
	char a[30];
	char ch;
	ofstream outfile("decompression.txt", ios::out);
	ifstream infile("compression_2.dat", ios::binary);
	if (!outfile)
	{
		cerr << "open error" << endl;
		exit(1);
	}
	if (!infile)
	{
		cerr << "open error" << endl;
		exit(1);
	}
	char m = 0;
	int point = 7;
	string s = "";
	while (length >=0)
	{
		if (point == 7)
		{
			infile.read((char *)&m, sizeof(char));
			length -= 8;
		}

		char ch = m;

		ch &= 1 << point;
		if (ch == 0)
			s += '0';
		else
			s += '1';
		point--;
		if (point < 0)
			point = 7;
		while (hafuman.count(s) == 0)
		{
			if (point == 7)
			{
				infile.read((char *)&m, sizeof(char));
				length -= 8;
			}
			char ch = m;

			ch &= 1 << point;
			if (ch == 0)
				s += '0';
			else
				s += '1';
			point--;
			if (point < 0)
				point = 7;
		}
		char t = hafuman[s];
		outfile << t;
		s = "";
	}
	cout << "解压成功!可以再decompression.txt文件中查看" << endl;
}
void compression_2(HuffmanCode code, vector<char> v, TNode node)
{
	int i, j, k;
	ifstream infile("compression.txt", ios::in);
	ofstream outfile("compression_2.dat", ios::binary);
	if (!outfile)
	{
		cerr << "open error" << endl;
		exit(1);
	}
	if (!infile)
	{
		cerr << "open error" << endl;
		exit(1);
	}
	char a=0;
	int point = 0;
	for (i = 0; i < v.size(); i++)
	{
		for (j = 0; j < node.length; j++)
		{
			if (node.data[j] == v[i])
			{
				break;
			}
		}
		
		for (k = 0; code[j + 1][k] != '\0'; k++)
		{
			if (code[j + 1][k] == '0')
				a &= ~(1 << (7-point));
			if (code[j + 1][k] == '1')
				a |= (1 << (7 - point));
			point++;
			if (point == 8)
			{
				outfile.write((char*)&a, sizeof(char));
				point = 0;
				a = 0;
			}
				
		}
	}
	if(point!=0)
		outfile.write((char*)&a, sizeof(char));
	outfile.close();
	cout << "压缩二进制文件成功!,可以到compression_2.dat中查看" << endl;
	Sleep(500);
}
int main()
{
	vector<char> str;
	fstream f;
	TNode tnode;
	initTnode(tnode);
	int number,n;
	HufumanTree hafutree;
	HuffmanCode hafuCode;
	int codelength=0;
	map<string, char> hafuman;
	while (1)
	{
		cout << "请输入选择的功能" << endl;
		cout << "1.压缩文件(文件名为test.txt,压缩后的文件名为compression_2.dat),编码的文件名为compression.txt中" << endl;
		cout << "2.解压文件(文件名为compression.txt),解压后的文件名为decompression.txt" << endl;
		cin >> number;
		switch (number)
		{
			case 1:
				Read(str);
				TNodeCount(tnode, str);
				n = tnode.length;
				CreateHuffmanTree(hafutree, tnode, n);
				CreatHuffmanCode(hafutree, hafuCode, n);
				compression(hafuCode, str, tnode);
				compression_2(hafuCode, str, tnode);
				initmap(hafuman, hafuCode,n,tnode,codelength);
				system("pause");
				break;
			case 2:
				decompression(hafuman,codelength);
				system("pause");
				break;
		default:
			cout << "输入错误!请重新输入";
			system("pause");
			break;
		}

	}
	return 0;
}



展开阅读全文

没有更多推荐了,返回首页