帮别人改的DS课设4

来源:互联网 发布:部队网络勾联策反 编辑:程序博客网 时间:2024/06/02 18:04

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//构造huffman树类型
typedef struct       
{
    char self;     //字符存储
    int weight;     //权值存储
    int parent,lchild,rchild; //结点存储
    int flag;      //存在判断
}HuffmanTree;
//构造huffman编码临时存储类型
typedef struct
{
    char cd[100];//编码临时存储
    int start;//编码起始点
}HuffmanCode;
//存储huffman编码
typedef struct
{
    char self;//字符存储
    char code[100];//编码存储
}CodeSaver;
//声明全局变量
HuffmanTree tree[100],newtree[100];//100为字符种类最大数
HuffmanCode code[100];//临时存储huffman编码
CodeSaver cd[100];//存储huffman编码
int weight_min1,weight_min2;  //weight_min1,weight_min2存储最小和次小的两个结点
int fchar_kindcount;//fchar_kindcount存储出现字符种类,在权值累加函数WeightAdd(HuffmanTree tree[100]);中统计文章中出现的字符种类
char name[20];//文件名在整个程序中有效
//打印huffman编码
void PrintHuffmanCode(HuffmanTree tree[],HuffmanCode code[],CodeSaver cd[])
{
 int i,k,j;
 printf("输出huffman编码:/n");
 for(i=0;i<fchar_kindcount;i++)
 {
  printf(" %c :",tree[i].self);//打印字符
   cd[i].self=tree[i].self;
    j=0;
  for(k=code[i].start;k<=fchar_kindcount;k++)//打印编码
  {
   printf(" %c ",code[i].cd[k]);
   cd[i].code[j]=code[i].cd[k];
   cd[i].code[j+1]=0;
   j++;
  }
  printf("/n");
 }
}
//构造huffman树编码
void CreateHuffmanCode(HuffmanTree tree[],HuffmanCode code[])
{
 int i,f,c;
 HuffmanCode d;
// d.cd[fchar_kindcount+1]='/0';
 for(i=0;i<fchar_kindcount;i++)
 {
  d.start=fchar_kindcount+1;
 
  for(c=i,f=tree[i].parent;f!=0;c=f,f=tree[f].parent)
  {
   if(tree[f].lchild==c)//左转为0
    d.cd[--d.start]='0';
   else
    d.cd[--d.start]='1';//右转为1 
  }
  code[i]=d; 
 }
}
void SelectMinNode(HuffmanTree tree[],int k)
/*在1~~~t之间选取w最小的下标s1,次最小的下标s2*/
{
 int i,w1,w2;/*w1为最小权重,w2为次最小权重*/
 w1=w2=32767;/*初始值为无穷大*/
 for(i=1;i<=k;i++)
  if(tree[i].parent==0)
  {
   if(tree[i].weight<w1)
   {
    w2=w1;/*找到了比最小还小的,就把最小的传给次最小的*/
    weight_min2=weight_min1;
    w1=tree[i].weight;
    weight_min1=i;
   }
   else if(tree[i].weight<w2)
   {
    w2=tree[i].weight;/*找到比最小大,而比次最小小的,就传给次最小的*/
    weight_min2=i;
   }
  }
}
//找寻parent为0,权最小的两个节点
/*void SelectMinNode(HuffmanTree tree[],int k) 
{
 int i;
 for (i=0;i<=k && tree[i].parent!=0 ;i++);//判断双亲是否为0
      weight_min1=i;//用weight_min1记录下:第一个双亲为0时,树的当前结点的下标
 
 //寻找最小和次小结点
 for (i=0;i<=k;i++)
  if (tree[i].parent==0 && tree[i].weight<tree[weight_min1].weight)
   weight_min1=i;//用weight_min1继续记录下:最后一个双亲为0且权值是双亲为0中最小的结点(即最小结点)的下标
 for (i=0; i<=k ; i++)
   if (tree[i].parent==0 && i!=weight_min1)
    break;
      weight_min2=i;//用weight_min2记录下:双亲为0中非最小结点的结点下标
 for (i=0;i<=k;i++)
    if ( tree[i].parent==0 && i!=weight_min1 && tree[i].weight<tree[weight_min2].weight)
   weight_min2=i;//用weight_min2记录下:双亲为0中非最小结点且权值是其中最小的结点(即次小结点)的结点下标
}*/
//生成huffman树
void CreateHuffmanTree(HuffmanTree tree[],int *w)

 int m,i;
 m=2*fchar_kindcount-1;//m为结点个数
 for (i=0;i<fchar_kindcount;i++)//初始化树但保留权值
 {
  tree[i].parent=0;
  tree[i].lchild=0;
  tree[i].rchild=0;
 }
 for (i=fchar_kindcount+1;i<=m;i++)
 { 
  tree[i].parent=0;
  tree[i].lchild=0;
  tree[i].rchild=0;
 }
 for (i=fchar_kindcount+1;i<=m;i++)
 {
  SelectMinNode(tree, i-1);//寻找最小和次小结点
  tree[weight_min1].parent=i;
  tree[weight_min2].parent=i;
  tree[i].lchild=weight_min1;
  tree[i].rchild=weight_min2;    
  tree[i].weight=tree[weight_min1].weight+tree[weight_min2].weight;//新结点权值等于最小和次小相加
 }
}
//字符->编码,编码->字符的查询
void CodeSearch(CodeSaver cd[])
{
 char ch[100],ch1;        //ch1存储要查询的字符,ch[]存储要查询的编码,x作判断
 int i,quit=0;
while(!quit)
{
  int x;
  printf("a.查询的字符/n");
  printf("b.查询的编码/n");
  printf("c.退出/n");
  x=getchar();
  if(x=='a')
  {
   printf("Input the char :");
   scanf("%s",&ch1);        //输入要查询的字符
   for(i=0;i<fchar_kindcount;i++)
   {
       if(cd[i].self==ch1)        //如遇相同则打印,否则退出
    {
          printf("The code is : %s/n",cd[i].code);
          break;
    }
       if(i==fchar_kindcount-1) printf("Not find!/n");
   }
  }
  else if(x=='b')
  {
   printf("Input the code :");
   scanf("%s",ch);        //输入要查询的编码
   for(i=0;i<fchar_kindcount;i++)
   {
    if(strcmp(cd[i].code,ch)==0)        //如遇相同则打印,否则退出
    {
     printf("The char is : %c/n",cd[i].self);
  //for(int a=0;a<100;a++)printf("%d",ch[a]);putchar('/n');
     break;
    }
    if(i==fchar_kindcount-1) printf("Not find!/n");
   }
  }
  else if(x=='c'){ quit=1;break;}
 }
}
//根据字符出现次数进行权值累加,文件操作在此函数进行
void WeightAdd(HuffmanTree tree[100]) 
{
 FILE *fp;
 char ch;
 int i;
 while(1)      
 {
  printf("请输入要查找的文件名(含扩展名且必须在工作区内):");
  scanf("%s",&name);
  fp=fopen(name,"r");
  if(fp==NULL)     //判断文件是否为空
  {
   printf("找不到指定文件!/n");
  }
  else
   break;
 }
 printf("/n");
 while(!feof(fp))     //读文件
 {
  ch=fgetc(fp);
  printf("%c",ch);
  for(i=0;i<100;i++)
  {
   if(tree[i].self==ch)  //如遇相同字符则自加一次
   {
    tree[i].weight++;
    tree[i].flag=1;   //在字符集中有出现,置标志为1
   }
  }
 }
 printf("/n");
 fclose(fp);
 for(i=0;i<100;i++)//统计文章中字符种类存入fchar_kindcount中
 {
  if(tree[i].flag==1)//该字符在文件中存在
   fchar_kindcount++;
 }
}
//将编码存放在code.txt内并打印之
void CodingFile()
{
 FILE *fp,*fp1;
 char ch;
 int i;
 while(1)      
 {
  fp=fopen(name,"r");
  if((fp1=fopen("code.txt","w"))==NULL)
  {
  printf("不能打开文件code.txt/n");
   exit(0);
  }
  if(fp==NULL)     //判断文件是否为空
  {
   printf("找不到指定文件!/n");
  }
  else
   break;
 }
 printf("/n");
 printf("编码序列如下(编码文件存放在code.txt内):/n");
 while(!feof(fp))     //读文件
 {
  ch=fgetc(fp);
  for(i=0;i<fchar_kindcount;i++)
  {
       if(cd[i].self==ch)        //如遇相同则打印,否则退出
    {
          fprintf(fp1,"%s",cd[i].code);
    printf("%s",cd[i].code);
          break;
    }
  } 
 }
 printf("/n");
 fclose(fp);
 fclose(fp1);
}
//将二进制编码文件译码到文件decode.txt内并打印在屏幕上
void DecodingFile()
{
 FILE *fp,*fp1;
 char ch,decode[100];
 int i,j=0;
 for(int k=0;k<100;k++)
  decode[k]=-52;
 while(1)      
 {
  printf("请输入要译码的文件名(含扩展名且必须在工作区内):");
  scanf("%s",&name);
  if((fp1=fopen("decode.txt","w"))==NULL)
  {
  printf("不能打开文件decode.txt/n");
   exit(0);
  }
  if((fp=fopen(name,"r"))==NULL)     //判断文件是否为空
  {
   printf("找不到指定文件!/n");
  }
  else
   break;
 }
 printf("/n");
 printf("译码序列如下(译码文件存放在decode.txt内):/n");
 /* for(i=0;i<fchar_kindcount;i++)
  {
 for(int a=0;a<100;a++)
  printf("%c",cd[i].code[a]);}*/
 int count=0;
 while(!feof(fp))     //读文件
 {
  ch=fgetc(fp);//putchar(ch);
  decode[j]=ch;
  decode[++j]=0;
  // printf("/t%d",decode[j++]);printf("/t%d",++count);putchar('/n');
  //puts(decode);
         
  for(i=0;i<fchar_kindcount;i++)
  {
  
       if(strcmp(cd[i].code,decode)==0)        //如遇相同则打印,否则退出
    {
          fprintf(fp1,"%c",cd[i].self);
    printf("%c",cd[i].self);
    for(k=0;k<100;k++)
     decode[k]=-52;
    j=0;
          break;
    }
  }
 }
 printf("/n");
 fclose(fp);
 fclose(fp1);
}
//进入哈夫曼编码译码器
void IntoHuffmanEncoder()
{
  int i,w[100],j=0;
  fchar_kindcount=0;
  //huffman树的初始化赋值
  for(i=32;i<=126;i++)//32是字符空格的ascii码,126是字符~的ascii码,从32到126包括了所有字符的ascii码  
  {
   tree[i-32].self=i;//存储字符集
   tree[i-32].weight=0;
   tree[i-32].parent=0;
   tree[i-32].lchild=0;
   tree[i-32].rchild=0;
   tree[i-32].flag=0;
  }
  for(i=0;i<100;i++)//初始化,中间权值变量传送构造哈夫曼树
  {
   w[i]=tree[i].weight;
  }
 
  WeightAdd(tree);  //调用函数进行权值累加
  printf("/n");
  if(fchar_kindcount!=0 && fchar_kindcount!=1)
  {
   for(i=0;i<100;i++)//中间权值变量传送构造哈夫曼树
   {
    w[i]=tree[i].weight;
   }
   for(i=0;i<100;i++)  //将出现的字符存入新树中
   {
    if(tree[i].flag==1)
    {
     newtree[j].self=tree[i].self;
     newtree[j].weight=tree[i].weight;
     newtree[j].parent=0;
     newtree[j].lchild=0;
     newtree[j].rchild=0;
     j++;
    }
   }
  CreateHuffmanTree(newtree,w);    //构造huffman树
  CreateHuffmanCode(newtree,code);   //构造huffman编码
  }
  else
  {
   printf("/n指定文件中只有1个字或者没有字!/n");
  }
}
//用户界面菜单函数
int menu()
{
 int d;
 int err=0;//异常处理标志
 printf("请选择所要进行的操作(提示必须先进入编译器才能打印出相应编码):/n");
 printf("1.进入哈夫曼编码译码器/n");
 printf("2.打印huffman编码/n");
 printf("3.对字符和编码的查找/n");
 printf("4.生成编码文件code.txt并将文件内容打印在屏幕上/n");
 printf("5.将二进制编码文件译码到文件decode.txt内并打印在屏幕上/n");
 printf("6.退出哈夫曼编码译码器/n");
 scanf("%d",&d);
 while(!err)//对用户的错误输入进行处理,原因是主函数中的switch(){}语句的参数如输入字母时将导致死循环
 {
   if(d!=1 && d!=2 && d!=3 && d!=4 && d!=5 && d!=6)
   {
       printf("请重新输入正确菜单编号(必须是1,2,3,4,5,6中的一个操作)!/n");//用户输入菜单编号有误,提醒用户重新选择
    scanf("%d",&d);
    err=0;//为对重新输入的数据进行判断,此时循环中无错误
   }
   else
    err=1;//为让合法输入能够被主函数调用,必须人为将标志位置为错误退出当前循环
 }
 return d;
}
void PrintProMember()
{

}
void main()
{
 int quit=0;
 int x,flag1=0,flag2=0;//flag1,flag2分别用来判断程序菜单选项的先后顺序合理性
 PrintProMember();//打印小组成员
    while(!quit)
        switch(menu())
   {
   case 1:flag1=1;IntoHuffmanEncoder();break;//进入哈夫曼编码译码器
   case 2:flag2=1;
    if(flag1==0) printf("请先进入哈夫曼编码译码器/n");
       else PrintHuffmanCode(newtree,code,cd);break;//打印huffman编码
   case 3:if(flag1==0) printf("请先进入哈夫曼编码译码器/n");
    else if(flag2==0) printf("请先打印huffman编码/n");
    else{ x=getchar();CodeSearch(cd); } break;      //对字符和编码的查找
   case 4:
    if(flag1==0) printf("请先进入哈夫曼编码译码器/n");
    else if(flag2==0) printf("请先打印huffman编码/n");
    else CodingFile();break;//打印huffman编码
   case 5:
    if(flag1==0) printf("请先进入哈夫曼编码译码器/n");
    else if(flag2==0) printf("请先打印huffman编码/n");
    else DecodingFile();break;//打印huffman编码
   case 6:quit=1;break;//退出哈夫曼编码译码器
   }
 system("pause");
}//end main

原创粉丝点击