#include"Huff_code.h"
HTree Init(HTree T);/*建立包含26个字母及其权值的huffman树*/
void Build_file(HTree T);/*打开文件hfmTree并将构造好的树输入*/
char* ENcoding(char* p,HTree T,int &len_1,int &len_2);/*对指针p指向的字符串编码并建立codefile存储结果,同时返回表示码值的字符串,记录编码前长度与编码后长度*/
void out_file(char* p);/*文件输出,p表示文件名*/
char* DEcoding(HTree T);/*对指针p指向的二进制码进行解码并建立textfile存储结果,同时返回解码的字符串*/
bool flag=0;/*对编码(解码)是否成功进行标记*/
void Output(char *e);
void output_all(HTree T); /*输出所有字母的编码*/
int main()
{
HTree c_table;
c_table=Init(c_table);
Build_file(c_table);
char baowen[] = "THIS PROGRAM IS MY FAVORITE";
char* e = baowen;
char bianma[400];
char* d = bianma;
int len_1 = 0;
int len_2 = 0;
d = ENcoding(e, c_table,len_1, len_2);
if (flag == 1)
{
flag = 0;
e = DEcoding(c_table);
}
Output(e);
cout << "编码前长度" << len_1 << '\t' << "编码后长度" << len_2 << '\n';
output_all(c_table);
return 1;
}
HTree Init(HTree T)
{
char data[27];
int weight[27]={186,64,13,22,32,103,21,15,47,57,1,5,32,20,57,63,15,1,48,51,80,23,8,18,1,16,1};
data[0] = ' ';
for (int i = 0; i < (26); i++)
{
data[i+1] = 'A' + i;
}
int i, k, s1, s2;
int min1, min2;
for (i = 0; i < MAX; i++)
{
T.Elem[i].data = data[i];
T.Elem[i].weight = weight[i];
T.Elem[i].parent = T.Elem[i].lchild = T.Elem[i].rchild = -1;
}
for (i = MAX; i <= 2*(MAX)-2; i++)
{
T.Elem[i].data = '\x2F';
T.Elem[i].parent = T.Elem[i].lchild = T.Elem[i].rchild = -1; /*初始化所有数据和相应权值、左右子节点*/
}
for (i = MAX; i < 2 * MAX - 1; i++) /*huffman树的建立*/
{
min1 = min2 = MAX_weight;
s1 = s2 = 0;
for (k = 0; k < i; k++)
{
if(T.Elem[k].parent==-1)
if (T.Elem[k].weight < min1) {
min2 = min1;
s2 = s1;
min1 = T.Elem[k].weight;
s1 = k;
}
else if (T.Elem[k].weight < min2)
{
min2 = T.Elem[k].weight;
s2 = k;
}
}
T.Elem[s1].parent = T.Elem[s2].parent = i;
T.Elem[i].lchild = s1;
T.Elem[i].rchild = s2;
T.Elem[i].weight = T.Elem[s1].weight + T.Elem[s2].weight;
}
T.num = MAX;
T.root = 2 *( MAX) - 2;
return T;
}
void Build_file(HTree T)
{
ofstream outfile("D:\\hfmTree.txt");
if (!outfile)
{
cout<<"can not open file htmTree"<<'\n';
}
else
{
cout << "build is ready"<<'\n';
char ch ;
int weight;
for (int i = 0; i <= T.root; i++)
{
outfile << i << "号节点:";
weight = T.Elem[i].weight;
outfile <<"权值"<<weight;
ch = T.Elem[i].data;
outfile << "数据" << ch << '\n';
outfile << "lchild" << " " << T.Elem[i].lchild << '\n';
outfile << "rchild" << " " << T.Elem[i].rchild << '\n';
}
outfile.close();
}
}
char* ENcoding(char* p,HTree T,int &len_1,int &len_2)
{
ofstream outfile("D:\\codefile.txt");
bool fla = 1;
if (!outfile)
{
cout << "can not open file codefile" << '\n';
fla = 0;
}
char bianma[400];
char* d = bianma;
char t[100];/*临时储存反序编码*/
int bit = 0;/*记录编码位数*/
char* temp = t;
for (int i = 0; p[i] != '\0'; i++)/*结束了一个字母的编码并输入codefile中,进行下一个字母的编码直到p字符串结束*/
{
len_1++;
int k = 0;
for (k = 0; k < MAX; k++)/*找到对应字母的节点*/
{
if (T.Elem[k].data == p[i])
{
break;
}
}
if (k == MAX)
{
cout << "编码失败,未找到对应字母" << '\n';
break;
}
for (int j = k; j != T.root && j < T.root;)/*从叶节点出发反向寻找根节点并记录反序的编码*/
{
Node Parent = T.Elem[T.Elem[j].parent];
if (Parent.lchild == j)
{
*temp = 0 + '0';
}
else
{
*temp = 1 + '0';
}
temp++;
bit++;
j = T.Elem[j].parent;
}
cout << '\n';
for (int j2 = bit-1; j2 >= 0; j2--)/*将反序编码调正*/
{
bianma[bit - 1 - j2] = t[j2];
if (fla)
outfile << t[j2];/*将编码输入文件*/
len_2++;
}
bianma[bit] = '\0';
bit = 0;
temp = &t[0];/*结束了一个字母的编码,进行下一个字母的编码*/
}
flag = 1;
outfile.close();
return d;
}
char* DEcoding(HTree T)
{
char tt[400]; /*几个数组的作用:tt[400]用来存放译码后的字母序列,q[1000]用来存放存储在文件中的二进制码*/
char* t = tt;
char q[1000];
char* qq = q;
ifstream infile("D:\\codefile.txt",ios::_Nocreate);
if (!infile)
{
cout << "can not open file codefile" << '\n';
}
else
{
cout << "成功打开codefile文件" << '\n';
char ch;
int countt = 0; /*int ch用于文件输入输出,countt用来记录数组q(即文件中的二进制位数)大小*/
while (infile>>ch)
{
q[countt] = ch;
cout << ch; /**/
countt++;
}
q[countt] = '\0';
infile.close();
ofstream outfile("D:\\textfile.txt");
bool fla = 1;
if (!outfile)
{
cout << "can not open file textfile" << '\n';
fla = 0;
}
int i = 0;/*i记录转化后字母的个数即tt[]数组的大小*/
int k = T.root;
int counttt;
for (counttt = 0; counttt < countt;)/*counttt用来记录当前循环所到达的位置*/
{
if (k < T.num) /*从根节点开始寻找,到第一个叶节点即视为找到编码对应字母,记录后继续寻找接下来编码对应的字母*/
{
tt[i] = T.Elem[k].data;
if (fla)
outfile << tt[i]; /*如果成功打开textfile文件,则将对应字母输入*/
i++;
k = T.root;
continue;
}
if (q[counttt] == '0')
k = T.Elem[k].lchild;
if (q[counttt] == '1')
k = T.Elem[k].rchild;
counttt++;
}
tt[i] = T.Elem[k].data;/*将最后一位输出*/
if (fla)
outfile << tt[i];
i++;
outfile.close();
tt[i] = '\0';
cout << '\n' << t << '\n';
return t;
}
}
void Output(char *e)
{
char name1[30] = "D:\\codefile.txt";
char name2[30] = "D:\\textfile.txt";
cout << "codefile" << "中的内容为:" << '\n';
out_file(name1);
cout << "textfile" << "中的内容为:" << '\n';
out_file(name2);
}
void out_file(char* p)
{
char ch;
ifstream infile(p);
infile.unsetf(ios::skipws);
if (!infile)
{
cout << "can not open file" << p << '\n';
}
else
{
while (infile>>ch)
{
cout << ch;
}
cout << '\n';
}
infile.close();
}
void output_all(HTree T)
{
int bit = 0;/*bit表示编码长度*/
char bianma[100];
char* d = bianma;
char t[100];
char* temp = t;
for (int i = 0;i<27; i++)
{
for (int j = i; j != T.root && j < T.root;)/*从叶节点出发反向寻找根节点并记录反序的编码*/
{
Node Parent = T.Elem[T.Elem[j].parent];
if (Parent.lchild == j)
{
*temp = 0 + '0';
}
else
{
*temp = 1 + '0';
}
temp++;
bit++;
j = T.Elem[j].parent;
}
for (int j2 = bit - 1; j2 >= 0; j2--)/*将反序编码调正*/
{
bianma[bit - 1 - j2] = t[j2];
}
bianma[bit] = '\0';
bit = 0;
cout << T.Elem[i].data << "编码为" << d << '\n';
temp = &t[0];/*结束了一个字母的编码,进行下一个字母的编码*/
}
}