算法思路如下:压缩:这个实验一开始将文件中的字符串读取到一个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;
}