Huffman编码

实验题目:Huffman编码

实验内容

  1. 将字符出现的频率作为结点的权值,构造一棵Huffman树,输出Huffman树各节点的值,输出各字符对应的Huffman编码。
    • 假设字符集c,字符频率集w如下:
      char c[]={a,b,c,d,e,f};
      int w[]={8,3,4,6,5,5};
      
  2. (选做) 输入待译码的信号,能正确进行译码。
    • 如:对输入信号10010001101111000能译出正确的字符序列abdefad

实验要求

  1. 构造一棵Huffman树

    • 新建项目,项目里新建文件“huffmanTree.h”,在“huffmanTree.h”里定义Huffman树的结点类型如下:
      typedef struct
      {     char data;	     //节点值
           double weight ;    //权值域
           int parent , lchild , rchild ;
      } HTNode ;  
      
    • 在“huffmanTree.h”里实现构造Huffman树的运算CreateHT
    • “main.cpp”里,由给定字符集c和字符频率集w定义初始数组变量如下:
      int w[]={8,3,4,6,5,5};	
      char c[]={'a','b','c','d','e','f'}; 
      int nums=6;
      
    • “main.cpp”里,定义Huffman结点数组如下:
      HTNode HT[2*nums-1];  //哈夫曼树结点数组
      
    • “main.cpp”里,赋初始dataweightHT数组如下:
      for(int i=0;i<nums;i++) 
      {
          HT[i].weight=w[i];
          HT[i].data=c[i];
      }
      
    • “main.cpp”里,调用构建Huffman树如下:
      CreateHT(HT,nums); //创建哈夫曼树
      
    • “main.cpp”里,显示Huffman树中各结点的值
      • (请补充以下代码)
  2. 求Huffman编码

    • 在“huffmanTree.h”里定义哈夫曼编码结点类型如下:
      #define N 10  //N的值大于n(想想为什么?)
      typedef struct
      {  
          char cd[N];  //存放当前节点的哈夫曼码
          int start;   //存放哈夫曼码在cd中的起始位置
      } HCode;	//哈夫曼编码结点类型
      
    • 在“huffmanTree.h”里实现Huffman树编码运算CreateHCode
    • “main.cpp”里,定义存放Huffman编码数组如下:
      HCode HC[nums]; 
      
    • “main.cpp”里,调用Huffman编码运算如下:
      CreateHCode(HT, HC, nums);
      
    • “main.cpp”里,显示各个字符对应的编码:
      • (请补充以下代码)
  3. 对输入信号进行译码

    • 在“huffmanTree.h”里实现Huffman译码运算EnHCode
    • “main.cpp”里,定义要译码的信号code及显示code信息如下:
      char code[]="10010001101111000";   //abdefad
      printf("\n\n待译码信号为:");
      for(int k=0;code[k]!='\0';k++)
      {
          printf("%c",code[k]);
      }
      
    • “main.cpp”里,定义字符数组DeCode用于保存译码后的字符串如下:
      char DeCode[20]; //保存译码后的字符串
      
    • “main.cpp”里,如果成功译码显示译码后的字符串。
      if( EnHCode(code,HT,DeCode,nums) )
      {
          printf("\n\n成功译码!");
          printf("\n译码后:");
          int i=0;
          while(DeCode[i] != '\0')
          {
              printf("%c",DeCode[i]);
              i++;
          }
      } 
      else
      {
          printf("\n\n代码错误!");
      }
      

实验过程记录

  • 运行结果如图:
    Huffman编码_第1张图片
完整代码如下:
#include 
#include 
#define N 10
typedef struct
{
    char data;     //节点值
    double weight;  //权值域
    int parent, lchild, rchild;
} HTNode;

typedef struct
{  
    char cd[N];  //存放当前节点的哈夫曼码
    int start;   //存放哈夫曼码在cd中的起始位置
}HCode;    //哈夫曼编码结点类型

void CreateHT(HTNode ht[],int n)
{   int i,j,k,lnode,rnode; float min1,min2;
    for (i=0;i<2*n-1;i++)    
        ht[i].parent = ht[i].lchild = ht[i].rchild = -1;
    for (i=n; i<2*n-1; i++)    
    {          min1 = min2 = 32767; 
        lnode = rnode = -1;
        for (k=0; k<=i-1; k++)
            if (ht[k].parent == -1)    //未构造二叉树的结点中查找
            {     if (ht[k].weight < min1)   //找最小的weight
            {    min2 = min1;    
                rnode = lnode;
                min1 = ht[k].weight; 
                lnode = k;  
            } else if (ht[k].weight < min2)   //找次小的weight
            {    min2 = ht[k].weight;
                rnode = k;  
            }   
            } //if
        ht[lnode].parent = i;
        ht[rnode].parent = i;
        ht[i].weight = ht[lnode].weight + ht[rnode].weight;
        ht[i].lchild = lnode;
        ht[i].rchild = rnode;
    }
    
} 
void initHT(HTNode ht[], int nums, int w[], char c[]) {
    for(int i=0;i<nums;i++) 
    {
        ht[i].weight=w[i];
        ht[i].data=c[i];
    }
}

void CreateHCode(HTNode ht[], HCode hcd[], int n)
{     int i,f,c; HCode hc;
    for (i=0; i<n; i++)    
    {     hc.start = n;   
        c = i ;   
        f = ht[i].parent;
        while ( f != -1)   
        {     if( ht[f].lchild == c )    
            hc.cd[hc.start--] = '0';
            else    
                hc.cd[hc.start--] = '1';
            c=f;  f=ht[f].parent; 
        }
        hc.start++;
        hcd[i]=hc;
    } 
} 
void printHT(HTNode ht[], int nums, char c[]) {
    for(int i=0;i<2*nums-1;i++)
    {
        if(i<=5){
            ht[i].data=c[i];
        }else
            ht[i].data='\0';
        printf("Node %-2d: data=%-2c, weight=%-2.0f, parent=%-2d, lchild=%-2d, rchild=%-2d\n", i, ht[i].data, ht[i].weight, ht[i].parent, ht[i].lchild, ht[i].rchild);
    }
}
void printHCode(HTNode ht[], HCode hcd[], int nums) {
    for(int i=0;i<nums;i++)
    {
        printf("Node %-2d: data=%-2c, Code=%s\n", i, ht[i].data,&hcd[i].cd[hcd[i].start]);
    }
}
int EnHCode(char code[], HTNode ht[], char DeCode[], int nums) {
    int i = 0, j = 0;
    while(code[i] != '\0') {
        if(code[i] == '0') {
            j = ht[j].lchild;
        } else if(code[i] == '1') {
            j = ht[j].rchild;
        } else {
            return 0;
        }
        if(ht[j].lchild == -1 && ht[j].rchild == -1) {
            DeCode[i] = ht[j].data;
            j = 0;
        }
        i++;
    }
    DeCode[i] = '\0';
    return 1;
    
}
int main()
{
    int w[] = {6, 3, 4, 8, 5, 5};
    char c[] = {'a', 'b', 'c', 'd', 'e', 'f'};
    int nums = 6;
    HTNode HT[2*nums-1];
    HCode HC[nums];
    initHT(HT, nums, w, c);
    CreateHT(HT,nums);
    printHT(HT, nums,c);
    printf("=============================================================\n");
    CreateHCode(HT, HC, nums);
    printHCode(HT, HC, nums);
    
    char code[]="10010001101111000";   //abdefad
    printf("\n\n待译码信号为:");
    for(int k=0;code[k]!='\0';k++)
    {
        printf("%c",code[k]);
    }
    printf("\n");
 
    char DeCode[20]; //保存译码后的字符串
    if( EnHCode(code,HT,DeCode,nums) )
    {
        printf("\n\n成功译码!");
        printf("\n译码后:");
        int i=0;
        while(DeCode[i] != '\0')
        {
            printf("%c",DeCode[i]);
            i++;
        }
    } 
    else
    {
        printf("\n\n代码错误!");
    }
    return 0;
}

【实验总结(个人心得)】
深入地了解了Huffman编码的原理和实现方法,实现了构造一棵Huffman树,输出树各节点的值,输出各字符对应的Huffman编码。但是,发现对于输入信号进行译码这部分内容实验失败。这可能是因为Huffman树构造或Huffman编码运算存在问题,导致无法正确地进行译码。

你可能感兴趣的:(算法,数据结构,c++,霍夫曼树)