哈夫曼编码器

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <limits.h>
# include <fstream>
# include <iostream>
using namespace std;
# define  maxsize 100
 
//将信息转化为哈夫曼码 
//康玉健
//17041114 
typedef struct 
{
    int order;//序号 
    char letter;//字母 
    int count;//出现的次数 
    
}LET;//字母 
typedef struct
{
    int weight;
    int parent;
    int left_child;
    int right_child;
    char elem;
    
}HTNode,*HuffmanTree;//定义哈弗曼树 
typedef struct
{
    char letter;
    char *code;
}CODE;//哈夫曼表 
typedef char**HuffmanCode;
void creat_HuffmanTree(HuffmanTree &HT,int n,LET *letter);//创建哈弗曼树
void HuffmanTree_select(HuffmanTree &HT,int num_node,int &s1,int &s2);//进行选择 
LET* statis_letter(char *data);//统计字母个数 
int statis_letternum(LET* letter);//统计含有字符多少个 
//LET *outcome(LET*letters);//返回最终的数组
void Huffman_code(HuffmanTree &HT,HuffmanCode &HC,int n);//创建哈夫曼编码表
void print_HuffmanCode(HuffmanCode &HC,LET *letter,int n);//打印哈夫曼表 
char* output_HuffmanCode(HuffmanCode &HC,char *data,int n,LET*letter);//输出哈夫曼编码 
//void resolve_HuffmanCode(HuffmanTree &HT,HuffmanCode HC,char *code)//解哈夫曼编码 
int  Root_Tree(HuffmanTree &HT,int n);   //得到哈夫曼树的根 
void resolve_HuffmanCode(HuffmanTree &HT,LET*letter2,char *code,int n);
LET* enter_weight(int len,LET* letter);//输入权值 
void output_huffman_to_file(HuffmanTree &HT,int len);//将哈夫曼树输入到文件中 
void Init(int len,LET* letter);//初始化功能 
HuffmanTree En_code(int len,LET* letter);//编码到一个文件中 
void De_code(HuffmanTree &HT,LET*letter2,char *code,int n);//译码部分
void print_code(void); 
void print_Tree(HuffmanTree &HT,int len);

int main(void)
{
    int flag=0;
    int returnmenu;
    int choice;
    printf("****************************************\n");
    printf("*              哈夫曼编码器            *\n");
    printf("*                  版本1.0             *\n");
    printf("*                                      *\n");
    printf("*                                      *\n");
    printf("*                                      *\n");
    printf("*                                      *\n");
    system("pause");
    system("cls");
    HuffmanTree HT=NULL; 
    char data[maxsize];
    char code[maxsize];
    printf("请输入一个您要进行编码的字符串:(长度小于100)\n");
    gets(data);
    LET*letter=statis_letter(data);//统计字符串中各个字母出现的频率 
    int len=statis_letternum(letter);
    LET*letter2= enter_weight(len,letter);
    do{
    
    system("cls");
    printf("*         【1】初始化                  *\n");
    printf("*         【2】编码                    *\n");
    printf("*         【3】译码                    *\n");
    printf("*         【4】印代码文件              *\n");
    printf("*         【5】打印哈夫曼树            *\n");
    printf("请输入您的选择:\n");
    scanf("%d",&choice);
    
    if(choice==1)
    {
    Init(len,letter2);
    }
    else if(choice==2)
    {
    
    HT=En_code(len,letter2);
    }
    else if(choice==3)
    {
    FILE* fp=fopen("编完码的结果.txt","r");
    if(fp==NULL)
    {
        printf("文件打不开!\n");
    }
    else
    {
        fscanf(fp,"%s",&code);
        fclose(fp);
        De_code(HT,letter2,code,len);
    }
    
}
else if(choice==4)
{ 

    print_code();
}
else if(choice==5)
{
  
    print_Tree(HT,len);
}
else
{
    printf("输入错误!\n");
}
printf("是否返回主菜单:\n");
printf("【1】是,【2】否\n");
scanf("%d",&returnmenu);
}
while(returnmenu==1);

}
void creat_HuffmanTree(HuffmanTree &HT,int n,LET*letters)//创建哈夫曼树 
{

    int m;
    int i;
    int j;
    int s1,s2; 
    if(n<=1)
    return ;
    m=2*n-1;
    HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
    HT[0].elem='#';
    HT[0].left_child=0;
    HT[0].right_child=0;
    HT[0].parent=0;
    HT[0].weight=0;
    for(i=1;i<=m;i++)
    {
        HT[i].elem='#';
        HT[i].parent=0;
        HT[i].left_child=0;
        HT[i].right_child=0;    
    }
    //依次输入%d个节点的位权值
    for(i=1;i<=n;i++)
    {
      HT[i].weight=letters[i-1].count;
      HT[i].elem=letters[i-1].letter;
    }
    //从1-i-1选择最小的两个节点并将权值返回给s1。s2
    for(i=n+1;i<=m;i++)
    {
        HuffmanTree_select(HT,i-1,s1,s2);
        HT[s1].parent=i;
        HT[s2].parent=i;
        HT[i].left_child=s1;
        HT[i].right_child=s2;
        HT[i].weight=HT[s1].weight+HT[s2].weight;
    }
     
    
 } 
 void HuffmanTree_select(HuffmanTree &HT,int num_node,int &s1,int &s2)//选择最小权值的下标 
 {
     int i;
    s1 = s2 = 0; 
    int min1 = INT_MAX;//最小值,INT_MAX在<limits.h>中定义的
    int min2 = INT_MAX;//次小值
 
    for ( i = 1; i <=num_node; ++i )
    {
    if ( HT[i].parent == 0 )
    {//筛选没有父节点的最小和次小权值下标
        if ( HT[i].weight < min1 )
        {//如果比最小值小
        min2 = min1;
         s2 = s1;
        min1 = HT[i].weight;
        s1 = i;
        }
        else if ( (HT[i].weight >= min1) && (HT[i].weight < min2) )
           {//如果大于等于最小值,且小于次小值
        min2 = HT[i].weight;
         s2 = i;
        }
        else
        {//如果大于次小值,则什么都不做
        ;
        }
    }
    }


 }
 LET* statis_letter(char *data)// 统计多少字符串之中各个字母数目 
 {
     int i,j;
     int len;
     int count=0;
    
    LET* letter=(LET*)malloc(26*sizeof(LET));

    for(i=0;i<26;i++)//依次把26个字母放到字母结构体数组之中 
    {
        letter[i].order=i;
        letter[i].letter='A'+i;
        letter[i].count=0;
    }
    
    for(i=0;i<strlen(data);i++)
    {
        for(j=0;j<26;j++)
        {
            if(letter[j].letter==data[i])
            {
                letter[j].count++;
            }
        }
       
    }
    
    return letter;
     
     
  } 
  int statis_letternum(LET* letter)//统计字母的个数 
  {
      int i;
      int count=0;
      for(i=0;i<26;i++)
      {
          if(letter[i].count!=0)
          {
              count++;
          }
    
      }
      return count;
   } 
/*LET *outcome(LET*letters)//把所有返回一个有全部字母的数组 
{
    int i;
    int counts=0;
    int len=statis_letternum(letters);
    LET *outcome=(LET*)malloc(len*sizeof(LET));
    for(i=0;i<26;i++)
    {
        if (letters[i].count!=0)
        {
            outcome[counts].letter=letters[i].letter;
            outcome[counts].order=letters[i].count;
            outcome[counts].order=letters[i].order;
            counts++;
        }
    }
    printf("count=%d",counts);
    return outcome;
}*/
void Huffman_code(HuffmanTree &HT,HuffmanCode &HC, int n)//哈夫曼编码树 
{
    int i;
    int c;
    int start;
    int f;
    
    HC=(HuffmanCode)malloc((n+1)*sizeof(char *));
    
    char *cd=(char*)malloc(n*sizeof(char));
    
    cd[n-1]='\0';
     
    for(i=1;i<=n;++i)
    {
        start=n-1;
        c=i;
        f=HT[i].parent;
        
        while(f!=0)
        {
            --start;
            if(HT[f].left_child==c)
            {
                cd[start]='0';
                    
            }
            else
            {
                cd[start]='1';
                
        }
            c=f;
            f=HT[f].parent;
            HC[i]=(char*)malloc((n-start)*sizeof(char));
            strcpy(HC[i],&cd[start]);
    
         } 
        
        
    
    }
    free(cd);
    
     
 }
 void print_HuffmanCode(HuffmanCode &HC,LET *letter,int n)
 {
     FILE* fp=fopen("编码表.txt","w");
     if(fp==NULL)
     {
         printf("文件打不开呀!兄弟!\n");
     }
     else
     {
     
     int i;
     for(i=0;i<n;i++)
     {
         if(letter[i].count!=0)
         {
         
         fprintf(fp,"字母:"); 
         fprintf(fp,"%c ",letter[i].letter);
         fprintf(fp,"权值:"); 
         fprintf(fp,"%d ",letter[i].count);
         fprintf(fp,"哈夫曼编码为:\n");
         fprintf(fp,"%s",HC[i+1]);
         fprintf(fp,"\n");
     }
         
         
     }
     fclose(fp);
    } 
 }
 char * output_HuffmanCode(HuffmanCode &HC,char *data,int n,LET* letter)
 {
        int i,j;
        CODE *HCode=(CODE*)malloc(n*sizeof(CODE));
        char *output_string=(char*)malloc(maxsize*sizeof(char));
        output_string[0]='\0';
        for(i=0;i<n;i++)
        {
            HCode[i].letter=letter[i].letter;
        }
       for(i=0;i<n;i++)
       {
           HCode[i].code=(char*)malloc(strlen(HC[i+1])*sizeof(char));
           strcpy(HCode[i].code,HC[i+1]);
        } 
        printf("转化为哈夫曼码为:\n");
        for(i=0;i<strlen(data);i++)
        {
            for(j=0;j<n;j++)
            {
                if(data[i]==HCode[j].letter)
                {
                    strcat(output_string,HCode[j].code);
                    printf("%s",HCode[j].code);
                }
            }
        }
        printf("\n");
        printf("传输的哈夫曼编码为:\n");
        puts(output_string);
        FILE* fp=fopen("编完码的结果.txt","w");
        if(fp==NULL)
        {
            printf("读取文件失败!\n");
        }
        else
        {
            for(i=0;i<strlen(output_string);i++)
            {
            if(i+1%50==0)
            {
                fprintf(fp,"\n");
            }
            fprintf(fp,"%c",output_string[i]);
        }
        }
        fclose(fp);
        return output_string;
    
        
  } 
  int  Root_Tree(HuffmanTree &HT,int n)  //返回哈弗曼树根节点的下标
  {
      int i;
      int m=2*n-1;
      for(i=1;i<=m;i++)
      {
          if(HT[i].parent==0)
          {
              break;
          }
      }
    return i;
      
   }
void resolve_HuffmanCode(HuffmanTree &HT,LET*letter2,char *code,int n)
{
    FILE* fp=fopen("译码的结果.txt","w");
    if(fp==NULL)
    {
        printf("文件打不开,我的朋友!\n");
    }
    else
    {
    
    int root=Root_Tree(HT,n); 
    int i=root;
    int weight; 
    do
    {
        
        if(*code=='0')//如果 
        {
            i=HT[i].left_child;
            
        }
        else if(*code=='1')
        {
           i=HT[i].right_child;
        }
        if(HT[i].left_child==0&&HT[i].right_child==0)//如果到达了叶子节点回到根节点 
        {
            weight=HT[i].weight;
            fprintf(fp,"%c",HT[i].elem);
             
            i=root;
            
        }
        code++;
}
while(*code!='\0');
fclose(fp);
}
 } 
LET* enter_weight(int len,LET* letter)
{   
    int i;
    int count=0;
    int weight;
    LET*letter2=(LET*)malloc(len*sizeof(LET)); 
    for(i=0;i<26;i++)
    {
        if(letter[i].count!=0)
        {
            printf("请输入%c的权值:\n",letter[i].letter);
            scanf("%d",&weight);
            letter2[count].count=weight;
            letter2[count].order=letter[i].order;
            letter2[count].letter=letter[i].letter;        
            count++;
    }
    }
    return letter2;
}  

void Init(int len,LET* letter)
{
    int i;
    int count=0;
    char data[maxsize];
    HuffmanCode HC=NULL;
    HuffmanTree HT=NULL;
    char code[100];
    
    creat_HuffmanTree(HT,len,letter);
    output_huffman_to_file(HT,len);

} 


void output_huffman_to_file(HuffmanTree &HT,int len)//打印哈夫曼树 
{
    char code[100];
    ofstream file;
    file.open("哈夫曼树.txt");
    for(int i=0;i<2*len;i++)
    {
        //file<<i<<" ";
        file<<HT[i].elem<<" ";
        file<<HT[i].weight<<" ";
        file<<HT[i].parent<<" ";
        file<<HT[i].left_child<<" ";
        file<<HT[i].right_child<<" ";
        file<<endl; 
    }
    file.close();
}  
HuffmanTree En_code(int len,LET* letter)//读取哈夫曼树并对其进行编码 
{
    //创建哈夫曼树 
    HuffmanTree HT_new=(HuffmanTree)malloc(2*len*sizeof(HTNode));
    //创建一个新的哈夫曼树
    //从文件中读取哈夫曼树
    char ch1,ch2;
    char elem;
    int weight;
    int parent;
    int left_child;
    int right_child;
    char code[100];
    HuffmanCode HC;
    FILE *fp=fopen("哈夫曼树.txt","r");

    for(int i=0;i<2*len;i++)
    {
        fscanf(fp,"%c",&elem);
        fscanf(fp,"%d",&weight);
        fscanf(fp,"%d",&parent);
        fscanf(fp,"%d",&left_child);
        fscanf(fp,"%d",&right_child);
        fscanf(fp,"%c%c",&ch1,&ch2);
        HT_new[i].elem=elem;
        HT_new[i].weight=weight;
        HT_new[i].parent=parent;
        HT_new[i].left_child=left_child;
        HT_new[i].right_child=right_child;
        
    } 
    //file.close();
    fclose(fp);
    for(int i=0;i<2*len;i++)
    {
        cout<<HT_new[i].elem<<" ";
        cout<<HT_new[i].weight<<" ";
        cout<<HT_new[i].parent<<" ";
        cout<<HT_new[i].left_child<<" ";
        cout<<HT_new[i].right_child<<endl; 
    }
    //打开要被编码的文件
    FILE *fp1=fopen("要被编码的数据.txt","r");
    fscanf(fp1,"%s",&code);
    fclose(fp1);
    Huffman_code(HT_new,HC,len);
    output_HuffmanCode(HC,code,len,letter);
    //打印哈夫曼树编码表
    print_HuffmanCode(HC,letter,len); 
    return  HT_new;
    
}
void De_code(HuffmanTree &HT,LET*letter2,char *code,int n)
{
    resolve_HuffmanCode(HT,letter2,code,n);
}
void print_code(void)
{
    char code[maxsize];
    FILE* fp=fopen("译码的结果.txt","r");
    if(fp==NULL)
    {
        printf("打不开文件啊,兄弟!\n");
        exit(-1);
     } 
     else
     {
         fscanf(fp,"%s",&code);
         fclose(fp);
     }
     printf("译码的结果为:\n");
     puts(code);
}
void print_Tree(HuffmanTree &HT,int len)
{
    FILE* fp=fopen("打印哈夫曼树.txt","w");
    if(fp==NULL)
    {
        printf("文件打不开!\n");
        exit(-1);
    }
    else
    {
        for(int i=0;i<2*len;i++)
        {
            fprintf(fp,"序号: ");
            fprintf(fp,"元素: ");
            fprintf(fp,"权值: ");
            fprintf(fp,"父母:  ");
            fprintf(fp,"左孩子: ");
            fprintf(fp,"右孩子:  ");
            fprintf(fp,"\n");
            fprintf(fp,"%d       ",i);
            fprintf(fp,"%c       ",HT[i].elem);
            fprintf(fp,"%d       ",HT[i].weight);
            fprintf(fp,"%d       ",HT[i].parent);
            fprintf(fp,"%d       ",HT[i].left_child);
            fprintf(fp,"%d       ",HT[i].right_child);
            fprintf(fp,"\n");
             
        }
        fclose(fp);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值