📄 ccc.cpp
字号:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <conio.h>
#include <windows.h>
#include <iostream.h>
#include <iomanip.h>
typedef struct {
int weight;
int parent,lchild,rchild;
} HTNode,*HuffmanTree;
typedef char **HuffmanCode;
typedef struct {
int s1;
int s2;
} MinCode;
char sbuf[1024];
/**************************************************************************
出错显示
***************************************************************************/
void Error(char *message)
{
system("cls");
fprintf(stderr,"Error:%s\n",message);
exit(1);
}
/**********************************************************************
选取权值最小的两个节点
***********************************************************************/
MinCode Select(HuffmanTree HT,int n) //从[1..n]中选
{
int min,secmin;
int temp;
int i,s1,s2,tempi;
MinCode code;
s1=1;s2=1;
for(i=1;i<=n;i++) //第一层循环
if(HT[i].parent==0) //i为第i个节点
{
min=HT[i].weight;
s1=i;
break;
}
tempi=i++; //记录第一层循环的位置
for(;i<=n;i++) //从第一层循环到的位置开始第二层循环找出比第一层循环中节点小的节点
if(HT[i].weight<min&&HT[i].parent==0) //选出第一个预选节点
{
min=HT[i].weight;
s1=i; //记录第一个预选节点的节点号
}
for(i=tempi;i<=n;i++) //从第一层循环到的位置开始第三层循环
if(HT[i].parent==0&&i!=s1) //选出第二个预选节点(为刚开始的节点后parent为0并且节点号不等于s1的那个)
{
secmin=HT[i].weight; //作为第二个预选节点号
s2=i; //记录第二个预选节点的节点号
break;
}
for(i=1;i<=n;i++) //再次从头开始第四层循环,找出比第三层循环小并且不等于第二层循环中s2的节点
if(HT[i].weight<secmin&&i!=s1&&HT[i].parent==0) // 以s2的权重为基准再次选取s2
{
secmin=HT[i].weight;
s2=i;
}
if(s1>s2) //如果s1的节点号大于s2的节点号则互换
{
temp=s1;
s1=s2;
s2=temp;
}
code.s1=s1;
code.s2=s2;
return code;
}
/******************************************************************
赫夫曼编码
********************************************************************/
void HuffmanCoding(HuffmanTree HT,HuffmanCode HC,int *w,int n)
{
int f,c,start,m;
int i,s1=0,s2=0;
HuffmanTree p;
char *cd;
MinCode min;
if(n<=1) Error("Code too small!");
m=2*n-1;
// HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); 重复分配空间了
for(p=HT+1,i=1;i<=n;i++,p++) //o not be used
{
p->weight=w[i]; //将设定的权值赋值到赫夫曼树的权值域
p->parent=0;
p->lchild=0;
p->rchild=0;
}
for(;i<=m;i++,p++)
{
p->weight=0; //不需要译码的权值都设为0
p->parent=0;
p->lchild=0;
p->rchild=0;
}
for(i=n+1;i<=m;i++)
{ //set up huffmantree
min=Select(HT,i-1); //select that node whose paraent are 0,and选出父节点是零
s1=min.s1; //weight are the smallest ,their number are并且权值最小的
s2=min.s2; //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;
}
printf("HT List:\n");
printf("Number\t\tweight\t\tparent\t\tlchild\t\trchild\n");
for(i=1;i<=m;i++)
printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\n", //打印所有节点的节点号,权值,父节点号,左孩子,右孩子
i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
// HC=(HuffmanCode)malloc((n+1)*sizeof(char *)); //分配n个字符编码的头指针向量,重复分配空间了
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,HC[i]中存储的是第i个节点的编码
}
free(cd); //释放空间
}
/**************************************************************************************
Initialization函数(建立赫夫曼树并将其存在文件hfmtree中)
**************************************************************************************/
void Initialization()
{
HuffmanTree HT=NULL; //赫夫曼树初始化为空
HuffmanCode HC=NULL; //赫夫曼编码初始化为空
char *ID=NULL;;//要翻译的字符的存储地址
int *w=NULL; //权值初始化为空
int n=0;//要翻译的字符数
int m;
FILE *htmTree,*num,*id/**code*/;
int i;
system("cls"); //清屏
printf("Input n:\n");
scanf("%d",&n); //设定需要译码的节点数
m=2*n-1;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
HC=(HuffmanCode)malloc((n+1)*sizeof(char *)); //分配n个字符编码的头指针向量
w=(int *)malloc((n+1)*sizeof(int *));//为这些需要译码的节点申请权值空间
ID=(char *)malloc((n+1)*sizeof(char));//为翻译的节点的ID申请空间
ID[0]=0;//第0号节点不用
w[0]=0; //第0号节点不用
printf("Enter ID and it's weight:\n"); //输入字母和权值
cout<<"i"<<","<<"ID"<<","<<"weight"<<endl;
for(i=1;i<=n;i++)
{
printf("%d,",i);
fgets(sbuf,1024,stdin);
scanf("%c,%d",&ID[i],&w[i]);
// scanf("%d",&w[i]);
//cout<<i<<" ";
//cin>>ID[i]>>w[i];
}
//调用赫夫曼编码
HuffmanCoding(HT,HC,w,n); //进行赫夫曼编码
printf("HuffmanCode:\n");
printf("Number\t\tID\t\tWeight\t\tCode\n");
for(i=1;i<=n;i++)
printf("%d\t\t%c\t\t%d\t\t%s\n",i,ID[i],w[i],HC[i]);//打印需要编码的节点的号码权值及编码
/**********************************************************************
将赫夫曼编码写入文件(包括需要翻译的字符,编码及其权值)
**********************************************************************/
cout<<"下面将赫夫曼编码写入文件"<<endl<<"...................."<<endl;
if((htmTree=fopen("htmTree.txt","w"))==NULL)
{
cout<<"can not open file"<<endl;
getch();
system("cls");
return;
}
if((num=fopen("num.txt","w"))==NULL)
{
cout<<"can not open file"<<endl;
getch();
system("cls");
return;
}
if((id=fopen("ID.txt","w"))==NULL)
{
cout<<"can not open file"<<endl;
getch();
system("cls");
return;
}
for(i=1;i<=n;i++)
fprintf(id,",%c",ID[i]);
for(i=1;i<=m;i++)
fprintf(htmTree,",%d,%d,%d,%d",HT[i].lchild,HT[i].parent,HT[i].rchild,HT[i].weight);
fprintf(num,"%d",n);
fclose(num);
fclose(htmTree);
fclose(id);
free(ID);
free(w);
free(HT);
free(HC);
cout<<"已将字符与对应编码写入根目录下文件htmTree.txt中"<<endl<<endl;
getch();
system("cls");
}
/*****************************************************************/
//从赫夫曼树文件读入内存
void readheffmantree(HuffmanTree HT,int n,char *ID,int m)
{
int i;
FILE *htmTree,*id;
if((htmTree=fopen("htmTree.txt","r"))==NULL)
{
cout<<"can not open file"<<endl;
getch();
system("cls");
return;
}
if((id=fopen("ID.txt","r"))==NULL)
{
cout<<"can not open file"<<endl;
getch();
system("cls");
return;
}
for(i=1;i<=n;i++)
fscanf(id,",%c",&ID[i]);
for(i=1;i<=m;i++)
fscanf(htmTree,",%d,%d,%d,%d",&HT[i].lchild,&HT[i].parent,&HT[i].rchild,&HT[i].weight);
fclose(htmTree);
fclose(id);
}
/*****************************************************************************************
获取报文并将其存入tobetran文件中(只存储要翻译的字符放到tobetran.txt中)
******************************************************************************************/
int InputCode()
{
char str[51];//录入要翻译的字符的临时存储区最大是50个字符
FILE *tobetran;
if((tobetran=fopen("tobetran.txt","w"))==NULL)
{
cout<<"不能打开文件"<<endl;
return 0;
}
cout<<"请输入你想要编码的字符"<<endl;
gets(str);
fprintf(tobetran,"%s",str);
cout<<"获取报文成功"<<endl;
fclose(tobetran);
return strlen(str);
free(str);
}
/************************************************************************************
编码函数(把翻译了的字符编码(字符在tobetran.txt中)放到codefile.txt中)
************************************************************************************/
void Encoding()
{
FILE *num,*tobetran,*codefile;
//先将编码字符的总字数读入内存
int n=0;
if((num=fopen("num.txt","r"))==NULL)
{
cout<<"can not open file"<<endl;
getch();
system("cls");
return;
}
fscanf(num,"%d",&n);
//现在为赫夫曼树和编码及字符申请空间
HuffmanTree HT=NULL; //赫夫曼树初始化为空
HuffmanCode HC=NULL; //赫夫曼编码初始化为空
char *ID=NULL;//要翻译的字符的存储地址
int m;
m=2*n-1;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
HC=(HuffmanCode)malloc((n+1)*sizeof(char *));
ID=(char *)malloc((n+1)*sizeof(char));//为翻译的节点的ID申请空间
//再将赫夫曼树和编码及字符读入内存
readheffmantree(HT,n,ID,m);
/*************************************************************************/
//再次求编码
char *cd;
int f,start,i,c;
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,HC[i]中存储的是第i个节点的编码
}
free(cd); //释放空间
/********************************************************************************/
//利用求得的编码来编码字符
char *tran;
i=99;
int j;
system("cls");
InputCode();
cout<<"下面对目录下文件tobetran.txt中的字符进行编码"<<endl;
if((tobetran=fopen("tobetran.txt","r"))==NULL)
{
cout<<"不能打开文件"<<endl;
}
if((codefile=fopen("codefile.txt","w"))==NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -