通过参考网上资料和自己调试,终于编写好了哈弗曼编码
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct node
{
int weight;
int parent;
int lchild;
int rchild;
};
struct Nchar
{
char n;
int weight;
char* code;
};
class huffman
{
int n;
string text;
node * huffTree;
Nchar * nchar,CharMapNode;
void select(int n, int &s1, int &s2);//查询权值最小的两项
public:
void gettext(char* CHAR);//读取文件内容
void savetext(char* CHAR);//将结果保存
void creattable();//根据读取文件内容,确定的权值,创建表
void CountCharsWeight();//统计读取的文件内容的各字符的权值
void display();//显示表,及权值
void coding();//编码
};
void huffman::gettext(char* CHAR)
{
ifstream into(CHAR);
if(!into)
{
cerr << "无法打开文件!" <<endl;
exit(0);
}
char a;
while(into.get(a))
{
text+=a;
}
}
void huffman::savetext(char* CHAR)
{
ofstream out(CHAR);
int m=2*n-1;
for(int a=1;a<=m;a++)
{
out<<a<<": rchild:"<<huffTree[a].rchild<<" lchild:"<<huffTree[a].lchild<<" parent:"<<huffTree[a].parent<<" weight:"<<huffTree[a].weight<<endl;
}
out<<"---------------------------------------------"<<endl;
for(int h=1;h<=n;h++)
{
out<<nchar[h].n<<"的权值为:"<<nchar[h].weight<<" 编码为:"<<nchar[h].code<<endl;
}
}
void huffman::select(int n, int &s1, int &s2)
{
s1 = s2 = 0;
for (int i = 1; i <= n; ++i)
{
if (huffTree[i].parent != 0)
continue;
if (s1 == 0)
s1 = i;
else if (s2 == 0)
{
//此处采用的策略,使得整个过程中s1的权值小于s2的权值
if (huffTree[i].weight < huffTree[s1].weight)
{
s2 = s1;
s1 = i;
}
else
s2 = i;
}
else
{
if (huffTree[i].weight < huffTree[s1].weight)
{
s2 = s1;
s1 = i;
}
else if (huffTree[i].weight < huffTree[s2].weight)
s2 = i;
}
}
}
void huffman::creattable()
{
huffTree = new node[2*n];
for(int m1=1;m1<=n;m1++)
{
huffTree[m1].lchild=0;
huffTree[m1].rchild=0;
huffTree[m1].parent=0;
huffTree[m1].weight=nchar[m1].weight;
}
for(int k=n+1;k<=2*n-1;k++)
{
huffTree[k].lchild=0;
huffTree[k].rchild=0;
huffTree[k].parent=0;
huffTree[k].weight=0;
}
int m = 2 * n - 1;
for (int i = n + 1; i <= m; ++i)
{
int s1,s2;
select(i - 1, s1, s2);
huffTree[s1].parent = huffTree[s2].parent = i;
huffTree[i].lchild = s1;
huffTree[i].rchild = s2;
huffTree[i].weight = huffTree[s1].weight + huffTree[s2].weight;
}
}
void huffman::CountCharsWeight()
{
int i = 0;
n = 0;
nchar = new Nchar[2];
nchar[1].n=text[i];
nchar[1].weight=1;
n++;
for(i=1;i<text.size();i++)
{
int j;
for (j = 1; j <= n; ++j) //遍历当前字符表,如果已存在该字符,权值+1
{
if (text[i] == nchar[j].n)
{
++nchar[j].weight;
break;
}
}
if(j>n)
{
++n;
Nchar* newchars = new Nchar[n + 1];
memcpy(newchars, nchar, n * sizeof(Nchar));
delete nchar;
nchar = newchars;
nchar[n].n = text[i];
nchar[n].weight = 1;
}
}
huffman::n=n;
}
void huffman::display()
{
int m=2*n-1;
for(int a=1;a<=m;a++)
{
cout<<a<<": rchild:"<<huffTree[a].rchild<<" lchild:"<<huffTree[a].lchild<<" parent:"<<huffTree[a].parent<<" weight:"<<huffTree[a].weight<<endl;
}
cout<<"---------------------------------------------"<<endl;
for(int h=1;h<=n;h++)
{
cout<<nchar[h].n<<"的权值为:"<<nchar[h].weight<<" 编码为:"<<nchar[h].code<<endl;
}
cout<<"---------------------------------------------"<<endl;
}
void huffman::coding()
{
//从叶子到根节点逆向求每个字符的哈弗曼编码
char *cd = new char[n]; //分配求编码的工作空间(每个字符编码结果最长n-1再加上'\0')
cd[n-1] = '\0'; //编码结束符
for(int i = 1; i <= n; ++i) //逐个字符求哈弗曼编码
{
int start = n - 1;
int c,f;
//从叶子到根逆向求编码
for (c = i, f = huffTree[i].parent; f != 0; c = f, f = huffTree[f].parent)
{
if (huffTree[f].lchild == c) //左孩子编码为0
cd[--start] = '0';
else //右孩子编码为1
cd[--start] = '1';
}
nchar[i].code = new char[n - start]; //为第i个字符编码分配空间
strcpy(nchar[i].code,&cd[start]);
}
delete cd;
}
void main()
{
huffman hum;
hum.gettext("text.txt");
hum.CountCharsWeight();
hum.creattable();
hum.coding();
hum.savetext("SaveText.txt");
hum.display();
}