求高手修改程序———哈夫曼编、译码器
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <malloc.h>
#include <stdio.h>
using namespace std;
const int UINT_MAX = 10000;//无符号整型的最大值
typedef struct
{
int weight;
int parent, lchild, rchild;
} HTNode, *HuffmanTree;//动态分配数组存储哈夫曼树
typedef char **HuffmanCode;//动态分配数组存储哈夫曼编码表
//-----------全局变量-----------------------
HuffmanTree HT;
HuffmanCode HC;
int *w,i,j,n,t;
char *z;
int flag = 0;
int numb = 0;
// -----------------求哈夫曼编码-----------------------
int min(HuffmanTree t, int i)//功能有待商榷
{// 函数void select()调用
int j, flag;
int k = UINT_MAX; // 取k为不小于可能的值
for (j = 1; j <= i; j++)
if (t[j].weight < k && t[j].parent == 0)//t[j]是树的根结点
k = t[j].weight, flag = j;
t[flag].parent = 1;//给选中的根节点的双亲赋1,避免第2次查找该结点
return flag;
}
//--------------------slect函数----------------------
void select(HuffmanTree t, int i, int &s1, int &s2)
{// 在i个结点中选择2个权值最小的树的根结点序号,s1为最小的两个值中序号小的那个
int j;
s1 = min(t, i);
s2 = min(t, i);
if (s1 > s2)
{
j = s1;
s1 = s2;
s2 = j;
}
}
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n)
{// w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC
int m, i, s1, s2, start;
unsigned c,f;
HuffmanTree p;
char *cd;
if (n <= 1)
return ;
//检测结点数是否可以构成树
m = 2 * n - 1;//n个叶结点,m为结点总数
HT = (HuffmanTree)malloc((m + 1) *sizeof(HTNode)); // 0号单元未用
for (p = HT + 1, i = 1; i <= n; ++i, ++p, ++w)//叶子结点初始化
{
(*p).weight = *w;//p所指向的结构体中weight赋值w
(*p).parent = 0;
(*p).lchild = 0;
(*p).rchild = 0;
}
for (; i <= m; ++i, ++p)//生成结点的双亲赋初值
{
(*p).weight = 0;
(*p).parent = 0;
(*p).lchild = 0;
(*p).rchild = 0;
}
for (i = n + 1; i <= m; ++i)// 建哈夫曼树
{// 在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
select(HT, i-1, s1, s2);
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lchild = s1;//权值小的结点做做孩子,便于编码、译码
HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
// 从叶子到根逆向求每个字符的哈夫曼编码
HC = (HuffmanCode)malloc((n + 1) *sizeof(char*));// 分配n个字符编码的头指针向量([0]不用)
cd = (char*)malloc(n *sizeof(char)); // 分配求编码的工作空间
cd[n - 1] = '\0'; // 编码结束符
for (i = 1; i <= n; i++)
{// 逐个字符求哈夫曼编码
start = n - 1; // 编码结束符位置
for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)// 从叶子到根逆向求编码
if (HT[f].lchild == c)
cd[--start] = '0';
else
cd[--start] = '1';
HC[i] = (char*)malloc((n - start) *sizeof(char));// 为第i个字符编码分配空间
strcpy(HC[i], &cd[start]); // 从cd复制编码(串)到HC
}
free(cd); // 释放工作空间
}//HuffanCoding
//--------------初始化哈夫曼树--------------------------------
//----------------输入字符集大小及n个字符及其权值,建立哈夫曼树,并存于hfmTree.txt中----------------------
void Initialization()
{
cout << "下面初始化哈夫曼链表" << endl << "请输入结点的个数n:"<<endl;
cin >> n;
w = (int*)malloc(n *sizeof(int));
z = (char*)malloc(n *sizeof(char));
cout << "请依次输入" << n << "个字符(字符型)\n(注意:必须以回车结束:)" <<endl;
for (i = 0; i < n; i++)
{
cout << "第" << i + 1 << "个字符:" << endl;
cin>>z[i];//输入字符存入字符数组Z中
}
cout << "请依次输入" << n << "个权值\n(注意:必须以回车结束):" << endl;
for (i = 0; i < n; i++)
{
cout << "第" << i + 1 << "个字符的权值:"<<endl;
cin>>w[i];//输入每个字符对应的权值存入权值数组w中
}
HuffmanCoding(HT, HC, w, n);//对输入的字符进行哈夫曼编码
//------------------------打印编码-------------------------------------------
cout << "字符对应的编码为:" << endl;
for (i = 1; i <= n; i++)
{
cout<<"字符"<<*(z+i-1)<<"的编码为"<<HC[i]<<endl;//输出字符对应的编码
}
//--------------------------将哈夫曼编码写入文件------------------------
cout << "下面将哈夫曼编码写入文件" << endl;
FILE *hfmTree;
char r[] =
{
' ', '\0'
};
hfmTree = fopen("hfmTree.txt", "w");
if (hfmTree == NULL)
{
cout << "不能打开hfmTree.txt文件" << endl;
return ;
}
fputs(z, hfmTree);//将z中的字符写入hfmTree指向的文件中
for(i = 1; i < n + 1; i++)
{
fputs(HC[i], hfmTree);
fputs(r, hfmTree);
//fputs(HC[i],hfmTree);//存的是编码?
}
fclose(hfmTree);
cout << "已将字符与对应编码写入根目录下文件hfmTree.txt中" << endl;
flag = 1;
}
//---------------------获取报文并写入文件---------------------------------
void InputChar ()
{
FILE *ToBeTran;
char str[100];
ToBeTran = fopen("ToBeTran.txt", "w");
if (ToBeTran == NULL)//有问题?
{
cout << "不能打开ToBeTran.txt文件" << endl;
return ;
}
cout << "请输入你想要编码的字符(串):" << endl;
cin>>str;
fputs(str, ToBeTran);
cout << "获取报文成功" << endl;
fclose(ToBeTran);
}
//---------------------编码函数---------------------------------
void Encoding()
{
InputChar ();
cout << "下面对目录下文件ToBeTran.txt中的字符进行编码" << endl;
FILE *ToBeTran, *CodeFile;
ToBeTran = fopen("ToBeTran.txt", "rb");
if (ToBeTran == NULL)
{
cout << "不能打开ToBeTran.txt文件" << endl;
}
CodeFile = fopen("CodeFile.txt", "w");//原来是"wb"
if (CodeFile == NULL)
{
cout << "不能打开CodeFile.txt文件" << endl;
}
char *tran;
i = 99;
tran = (char*)malloc(100 *sizeof(char));
while (i == 99)
{
if (fgets(tran, 100, ToBeTran) == NULL)
{
cout << "不能打开ToBeTran.txt文件" << endl;
break;
}
for (i = 0; tran [i] != '\0'; i++)
{
for (j = 1; j <= n; j++)
{
if (z [j - 1] == tran [i])
{
fputs(HC[j], CodeFile);
if (j > n)
{
cout << "字符错误,无法编码!" << endl;
break;
}
}
}
}
}
cout << "编码工作完成" << endl << "编码写入目录下的CodeFile.txt中" <<endl;
fclose(ToBeTran);
fclose(CodeFile);
free(tran);
}
//-----------------译码函数---------------------------------
void Decoding()
{
cout << "下面对根目录下文件CodeFile.txt中的字符进行译码" << endl;
FILE *codef, *txtfile;
txtfile = fopen("TextFile.txt", "w");
if (txtfile == NULL)
{
cout << "不能打开TextFile.txt文件" << endl;
}
codef = fopen("CodeFile.txt", "r");
if (codef == NULL)
{
cout << "不能打开CodeFile.txt文件" << endl;
}
char *work, *work2, i2;
int i4 = 0, i, i3;
unsigned long length = 10000;
work = (char*)malloc(length *sizeof(char));
fgets(work, length, codef);
work2 = (char*)malloc(length *sizeof(char));
i3 = 2 * n - 1;
for (i = 0; work [i - 1] != '\0'; i++)//有待思考?是0还是NULL
{
i2 = work [i];
if (HT[i3].lchild == 0)//
{
work2 [i4] = z[i3 -1];
i4++;
i3 = 2 * n - 1;
i--;
}
else if (i2 == '0')//
i3 = HT[i3].lchild;
else if (i2 == '1')//
i3 = HT[i3].rchild;
}
work2 [i4] = '\0';//有待思考'\0'
fputs(work2, txtfile);
cout << "译码完成" <<endl<< "内容写入根目录下的文件TextFile.txt中" <<endl;
//cout <<"译码为:"<< work2<<endl;//输出译码
free(work);
free(work2);
fclose(txtfile);
fclose(codef);
}
//-----------------------打印编码的函数----------------------
void Code_printing()
{
cout << "下面打印根目录下文件CodePrin.txt中编码字符" << endl;
FILE *CodePrin, *codefile;
CodePrin = fopen("CodePrin.txt", "w");
if (CodePrin == NULL)
{
cout << "不能打开CodePrin.txt文件" << endl;
return ;
}
codefile = fopen("CodeFile.txt", "r");
if (codefile == NULL)
{
cout << "不能打开CodeFile.txt文件" << endl;
return ;
}
char *work3;
work3 = (char*)malloc(51 *sizeof(char));
//do
//{
if (fgets(work3, 51, codefile) == NULL)
{
cout << "不能读取CodeFile.txt文件" << endl;
//break;
}
fputs(work3, CodePrin);
cout<<work3<<endl;
//}while (strlen(work3) == 50);
free(work3);
int iNum=2,num=2;
while((num=fscanf(codefile,"%d",iNum))!=0)//有待思考'\0'
{
printf("%d",iNum);
fprintf(CodePrin,"%d",iNum);
}
cout << "打印工作结束" << endl << endl;
fclose(CodePrin);
fclose(codefile);
}
//打印编码有问题
//------------------------打印哈夫曼树的函数-----------------------
void coprint(HuffmanTree start, HuffmanTree HT)//start为形参
{
if (start != HT)
{
FILE *TreePrint;
TreePrint = fopen("TreePrint.txt", "a");
if (TreePrint == NULL)
{
cout << "创建TreePrint.txt文件失败" << endl;
return ;
}
numb++; //该变量为已被声明为全局变量
coprint(HT + start->rchild, HT);
cout << setw(5 *numb) << start->weight << endl;
fprintf(TreePrint, "%d\n", start->weight);
coprint(HT + start->lchild, HT);
numb--;
fclose(TreePrint);
}
}
void Tree_printing(HuffmanTree HT, int w)
{
HuffmanTree p;
p = HT + w;
cout << "下面打印哈夫曼树" << endl;
coprint(p, HT);
cout << "打印工作结束" << endl;
}
//------------------------主函数------------------------------------
int main()
{
char choice;
while (choice != 'q')
{
cout << "******************************" << endl;
cout << " 欢迎使用哈夫曼编码解码系统" << endl;
cout << "******************************" << endl;
cout << "(1)要初始化哈夫曼链表请输入'i'" << endl;
cout << "(2)要编码请输入'e'" << endl;
cout << "(3)要译码请输入'd'" << endl;
cout << "(4)要打印编码请输入'p'" << endl;
cout << "(5)要打印哈夫曼树请输入't'" << endl;
cout << "(6)要离开请输入'q'" << endl;
if(flag==0)cout<<"第一次使用时请先初始化哈夫曼链表,输入'i'"<<endl;
cin >> choice;
switch (choice)
{
case 'i':Initialization();break;
case 'e':Encoding();break;
case 'd':Decoding();break;
case 'p':Code_printing();break;
case 't':Tree_printing(HT, 2 *n - 1);break;
case 'q':cout<<"****感谢适用本系统,再见!****"<<endl;break;
default:cout << "输入错误,请重新输入" << endl;
}
}
free(z);
free(w);
free(HT);
return 0;
}
以上程序要求
一个完整的系统已具有以下功能:
(1)I:初始化。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
(2)E:编码。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果粗如文件CodeFile中。
(3)D:译码。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入TextFile中。
(4)P:印代码文件。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。
(5)T:印哈夫曼树。将已在内存中的哈夫曼树以直观的方式(树或凹凸表形式)显示在终端上,同时将此字符形式的哈夫曼树写入TreePrin中。
目前的问题是:(1):hfmTree中不能存哈夫曼树HT,暂且存的HC,
(2):打印代码文件出现的全是2,且不会停止
希望高手帮忙看看,小弟不胜感激