输入字符集以及权值,建立哈夫曼树进行一系列操作;其中建立哈夫曼树,以及编码部分参考了百度百科;
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
const int MAXVALUE = 99999; //初始设定的权值最大值
const int MAXBIT = 10; //初始设定的最大编码位数
const int MAXN = 1000; //初始设定的最大结点个数
struct HaffNode //哈夫曼树的结点结构
{
int weight; //权值
int flag; //标记
int parent; //双亲结点下标
int leftChild; //左孩子下标
int rightChild; //右孩子下标
};
struct Code //存放哈夫曼编码的数据元素结构
{
int bit[MAXBIT]; //数组
int start; //编码的起始下标
int weight; //字符的权值
};
void Menu();
void Haffman(int weight[], int n, HaffNode haffTree[]);//建树
void HaffmanCode(HaffNode haffTree[], int n, Code haffCode[]);//生成哈夫曼编码
void Coding(char str[], char s[], int n, Code code[]);
void DeCoding(int n, char s[], HaffNode hafftree[]);
void ReadFile(char s[]);
void PreOrder(HaffNode haffTree[], int n);
void InOrder(HaffNode haffTree[], int n);
int main()
{
int i, weight[MAXN], len;
char strChar[MAXN], c;
bool flag = true;
HaffNode *hafftree;
Code *haffcode;
Menu();
while(flag)
{
cout << "please input:";
cin >> c;
switch(c)
{
case 'B':
{
cout << "please input string:";
cin>>strChar;
len = strlen(strChar);
cout << "please input weight:";
for(i=0; i<len; i++)
cin >> weight[i];
hafftree = new HaffNode[2*len-1];
Haffman(weight, len, hafftree);
}
break;
case 'E':
{
haffcode = new Code[len];
HaffmanCode(hafftree, len, haffcode);
}
break;
case 'T':
{
PreOrder(hafftree, 2*len-2);
cout << endl;
InOrder(hafftree, 2*len-2);
cout << endl;
}
break;
case 'C':
{
char strInput[MAXN];
cout << "please input string:";
cin >> strInput;
Coding(strInput, strChar, len, haffcode);
}
break;
case 'D':
{
DeCoding(len, strChar, hafftree);
}
break;
case 'P':
{
ReadFile("textfile.txt");
ReadFile("codefile.txt");
ReadFile("result.txt");
}
break;
case 'X':
{
flag = false;
}
break;
case 'S':
{
Menu();
}
break;
default:
break;
}
}
return 0;
}
void Menu()
{
cout<<"********************************************************************"<<endl;
cout<<"* B—建树: 读入字符集和各字符频度,建立哈夫曼树。*****************"<<endl;
cout<<"********************************************************************"<<endl;
cout<<"* T—遍历: 先序和中序遍历二叉树。 *****************"<<endl;
cout<<"********************************************************************"<<endl;
cout<<"* E—生成编码: 根据已建成的哈夫曼树,产生各字符的哈夫曼编码。*******"<<endl;
cout<<"********************************************************************"<<endl;
cout<<"* C—编码: 输入由字符集中字符串组成的任意字符串,利用已生成的 ****"<<endl;
cout<<"* 哈夫曼编码,显示编码结果,并将输入的字符串及其编码 ****"<<endl;
cout<<"* 结果分别保存在磁盘文件textfile.txt和codefile.txt中。***"<<endl;
cout<<"********************************************************************"<<endl;
cout<<"* D—译码: 读入codefile.txt,利用建议建成的哈夫曼树进行译码,******"<<endl;
cout<<"* 并将译码结果放入磁盘文件result.txt。 ******"<<endl;
cout<<"********************************************************************"<<endl;
cout<<"* P—打印: 屏幕显示文件textfile.txt、codefile.txt和result.txt。***"<<endl;
cout<<"********************************************************************"<<endl;
cout<<"* X—退出。 ******************************"<<endl;
cout<<"********************************************************************"<<endl;
}
void Haffman(int weight[], int n, HaffNode haffTree[])
//建立叶结点个数为n权值为weight的哈夫曼树haffTree
{
int j, m1, m2, x1, x2;
//哈夫曼树haffTree初始化。n个叶结点的哈夫曼树共有2n-1个结点
for(int i = 0; i < 2 * n - 1 ; i++)
{
if(i < n)
haffTree[i].weight = weight[i];
else
haffTree[i].weight = 0;
haffTree[i].parent = 0;
haffTree[i].flag = 0;
haffTree[i].leftChild = -1;
haffTree[i].rightChild = -1;
}
//构造哈夫曼树haffTree的n-1个非叶结点
for(i = 0;i < n-1;i++)
{
m1 = m2 = MAXVALUE;
x1 = x2 = 0;
for(j = 0; j < n+i;j++)
{
if (haffTree[j].weight < m1 && haffTree[j].flag == 0)
{
m2 = m1;
x2 = x1;
m1 = haffTree[j].weight;
x1 = j;
}
else if(haffTree[j].weight < m2 && haffTree[j].flag == 0)
{
m2 = haffTree[j].weight;
x2 = j;
}
}
//将找出的两棵权值最小的子树合并为一棵子树
haffTree[x1].parent = n + i;
haffTree[x2].parent = n + i;
haffTree[x1].flag = 1;
haffTree[x2].flag = 1;
haffTree[n+i].weight = haffTree[x1].weight + haffTree[x2].weight;
haffTree[n+i].leftChild = x1;
haffTree[n+i].rightChild = x2;
}
}
void HaffmanCode(HaffNode haffTree[], int n, Code haffCode[])
//由n个结点的哈夫曼树haffTree构造哈夫曼编码haffCode
{
Code *cd = new Code;
int child, parent;
//求n个叶结点的哈夫曼编码
for(int i = 0; i < n; i++)
{
cd->start = n-1; //不等长编码的最后一位为n-1
cd->weight = haffTree[i].weight; //取得编码对应权值的字符
child = i;
parent = haffTree[child].parent;
//由叶结点向上直到根结点
while(parent != 0)
{
if(haffTree[parent].leftChild == child)
cd->bit[cd->start] = 0; //左孩子结点编码0
else
cd->bit[cd->start] = 1;//右孩子结点编码1
cd->start--;
child = parent;
parent = haffTree[child].parent;
}
//保存叶结点的编码和不等长编码的起始位
for(int j = cd->start+1; j < n; j++)
haffCode[i].bit[j] = cd->bit[j];
haffCode[i].start = cd->start;
haffCode[i].weight = cd->weight; //保存编码对应的权值
}
}
void Coding(char str[], char s[], int n, Code code[])
{
ofstream outf("textfile.txt");
int len = strlen(str);
if(!outf)
{
cout << "cannot open the file\n";
return ;
}
outf << str;
outf << endl;
outf.close();
ofstream outfc("codefile.txt");
if(!outfc)
{
cout << "cannot open the file\n";
return ;
}
for(int i=0; i<len; i++)
{
for(int j=0; j<n; j++)
{
if(str[i] == s[j])
break;
}
for(int k=code[j].start+1; k<n; k++)
outfc << code[j].bit[k];
}
outfc << endl;
outfc.close();
}
void DeCoding(int n, char s[], HaffNode hafftree[])
{
ifstream inf("codefile.txt");
char str[MAXN];
inf >> str;
ofstream outf("result.txt");
int len = strlen(str);
int j = 2 * n - 2;
for(int i=0; i<len; i++)
{
if('0' == str[i])
{
if(0 <= hafftree[j].leftChild && hafftree[j].leftChild < n)
{
outf << s[hafftree[j].leftChild];
j = 2 * n - 2;
}
else
j = hafftree[j].leftChild;
}
else
{
if(0 <= hafftree[j].rightChild && hafftree[j].rightChild < n)
{
outf << s[hafftree[j].rightChild];
j = 2 * n - 2;
}
else
j = hafftree[j].rightChild;
}
}
inf.close();
outf.close();
}
void ReadFile(char s[])
{
ifstream inf(s);
char str[MAXN];
inf >> str;
cout << s << ":" << str << endl;
inf.close();
}
void PreOrder(HaffNode haffTree[], int n)
{
if(n > -1)
{
cout << haffTree[n].weight << " ";
PreOrder(haffTree, haffTree[n].leftChild);
PreOrder(haffTree, haffTree[n].rightChild);
}
}
void InOrder(HaffNode haffTree[], int n)
{
if(n > -1)
{
InOrder(haffTree, haffTree[n].leftChild);
cout << haffTree[n].weight << " ";
InOrder(haffTree, haffTree[n].rightChild);
}
}