• 哈夫曼编码与解码的C++实现:建立哈夫曼树、进行哈夫曼编码与解码


      最近完成了数据结构课程设计,被分到的题目是《哈夫曼编码和解码》,现在在这篇博文里分享一下自己的成果。

      我在设计时,在网上参考了很多老师和前辈的算法和代码,向他们表示感谢!他们的成果给了我很多启示和帮助。另外,自己的成品中也还有很多不完善的地方,欢迎批评指正。

    课题:哈夫曼编码与解码 C++代码实现

    (1)统计某电文中字符出现的频率(假设电文中只含有大小写英文字母,以及逗号和点号);
    (2)把字符出现的频率作为权值建立哈夫曼树,进行哈夫曼编码,并输出每个字符的编码结果;
    (3)对电文进行哈夫曼编码;
    (4)把电文的哈夫曼编码进行译码,输出对应电文的内容。

      1 #include <stdlib.h>
      2 #include <stdio.h>
      3 #include <malloc.h>
      4 #include <string.h>
      5 #include <ctype.h>
      6 #define MAX 999999 //一个极大值
      7 #define NUM 10
      8 
      9 //存储哈夫曼树每个结点
     10 typedef struct Node {
     11     char ch;
     12     int weight; //权值
     13     int parent;
     14     int lchild,rchild;
     15 }HFNode;
     16 //存储每个字符及其哈夫曼编码
     17 typedef struct {
     18     char ch;
     19     char code[NUM];
     20 }HFCharCode;
     21 
     22 HFNode HT[28*2-1]; //哈夫曼树结构体
     23 HFCharCode HCD[28]; //哈夫曼编码结构体
     24 int LeafNum; //叶子结点数
     25 int NodeNum; //所有结点数
     26 char EnterStr[MAX]; //输入的待编码电文
     27 char EnterCode[MAX]; //输入的待解码密文
     28 char RealStr[MAX]; //密文解码后的电文
     29 int AllWeight[28]; //存储所有28个字符的权值
     30 
     31 void Statistics();
     32 void CreateHFTree();
     33     void SelectMin(int &min1, int &min2);
     34 void CreateHFCode();
     35     void ReverseStr(char *str);
     36 void EncodeStr();
     37 void DecodeHFCode();
     38 
     39 int main() {
     40     printf("****** 哈夫曼编码与解码 ******
    
    ");
     41     printf("*** 输入一串字符串 ***
    ");
     42     scanf("%s", EnterStr);
     43     getchar();
     44     Statistics();
     45     CreateHFTree();
     46     CreateHFCode();
     47     EncodeStr();
     48     printf("
    *** 输入想解码的内容 ***
    ");
     49     scanf("%s", EnterCode);
     50     getchar();
     51     DecodeHFCode();
     52     return 0;
     53 }
     54 
     55 //统计每个字符权值
     56 void Statistics() {
     57     int len = strlen(EnterStr);
     58     for(int i = 0; i <= 27; i++)
     59         AllWeight[i] = 0;
     60     for(int j = 0; j <= len - 1; j++) {
     61         if(isalpha(EnterStr[j])) {
     62             EnterStr[j] = tolower(EnterStr[j]);
     63             AllWeight[EnterStr[j]-'a']++;
     64         }
     65         else if((int)EnterStr[j] == 44)
     66             AllWeight[26]++;
     67         else if((int)EnterStr[j] == 46)
     68             AllWeight[27]++;
     69         else {
     70             printf("
    输入不符合要求!
    
    ");
     71             exit(-1);
     72         }
     73     }
     74     int i = 0, j = 0;
     75     for( ; i <= 25; i++) {
     76         if(AllWeight[i] != 0) {
     77                 HT[j].weight  = AllWeight[i];
     78                 HT[j].ch = i+'a';
     79                 j++;
     80         }
     81     }
     82     if(AllWeight[i] != 0) {
     83             HT[j].weight = AllWeight[i];
     84             HT[j].ch = ',';
     85             j++;
     86             i++;
     87     }
     88     if(AllWeight[i] != 0) {
     89             HT[j].weight = AllWeight[i];
     90             HT[j].ch = '.';
     91     }
     92     printf("
    *** 打印每个字符的权值 ***
    ");
     93     int n = 0;
     94     for(int i = 0; i <= 27; i++) {
     95         if(AllWeight[i] != 0) {
     96             n++;
     97             if(i <= 25)
     98                 putchar('a'+i);
     99             else if(i == 26)
    100                 printf(",");
    101             else
    102                 printf(".");
    103             printf(": %d
    ", AllWeight[i]);
    104         }
    105     }
    106     LeafNum = n;
    107     NodeNum = 2*LeafNum-1;
    108 }
    109 
    110 //构造哈夫曼树
    111 void CreateHFTree() {
    112     int i;
    113     for(i = 0; i <= LeafNum-1; i++) {
    114         HT[i].parent = -1;
    115         HT[i].lchild = -1;
    116         HT[i].rchild = -1;
    117         HT[i].weight = HT[i].weight;
    118     }
    119     for(; i <= NodeNum-1; i++) {
    120         HT[i].parent = -1;
    121         HT[i].lchild = -1;
    122         HT[i].rchild = -1;
    123         HT[i].weight = MAX;
    124     }
    125     int min1, min2;
    126     for(i = LeafNum; i <= NodeNum-1; i++) {
    127         SelectMin(min1, min2);
    128         HT[min1].parent = i;
    129         HT[min2].parent = i;
    130         HT[i].lchild = min1;
    131         HT[i].rchild = min2;
    132         HT[i].weight = HT[min1].weight + HT[min2].weight;
    133     }
    134     // printf("
    *** 打印哈夫曼树 ***
    ");
    135     // for(int i = 0; i <= NodeNum-1; i++) {
    136     //     printf("序号:%d 字符:%c 权值:%d 双亲:%d 左孩:%d 右孩:%d
    ", i, HT[i].ch, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
    137     // }
    138 }
    139     //找到两个权值最小的二叉树的序号
    140     void SelectMin(int &min1, int &min2) {
    141         int i = 0;
    142         int temp;
    143         int wetmin1, wetmin2;
    144         while(HT[i].parent != -1) 
    145             i++;
    146         wetmin1 = HT[i].weight;
    147         min1 = i;
    148         i++;
    149         while(HT[i].parent != -1) 
    150             i++;
    151         wetmin2 = HT[i].weight;
    152         min2 = i;
    153         i++;
    154         if(wetmin1 > wetmin2) {
    155             temp = wetmin2;
    156             wetmin2 = wetmin1;
    157             wetmin1 = temp;
    158             temp = min2;
    159             min2 = min1;
    160             min1 = temp;
    161         }
    162         for(; i <= NodeNum-1; i++) {
    163             if(HT[i].weight < wetmin1 && HT[i].parent == -1) {
    164                 wetmin2 = wetmin1;
    165                 wetmin1 = HT[i].weight;
    166                 min2 = min1;
    167                 min1 = i;
    168             } else if(HT[i].weight < wetmin2 && HT[i].parent == -1) {
    169                 wetmin2 = HT[i].weight;
    170                 min2 = i;
    171             }
    172         }
    173     }
    174 
    175 //进行哈夫曼编码
    176 void CreateHFCode() {
    177     int i, j, len; 
    178     for(i = 0; i <= LeafNum-1; i++) {  
    179         len = 0;  
    180         j = i;
    181         HCD[i].ch = HT[j].ch;
    182         while(HT[j].parent != -1) {  //不是根节点
    183             if(HT[HT[j].parent].lchild == j) {  //是双亲结点的左孩子
    184                 HCD[i].code[len++] = '0'+0;  //加上字符0
    185             }else  //是右孩子
    186                 HCD[i].code[len++] = '0'+1;  //加上字符1
    187             j = HT[j].parent;  //往上遍历
    188         }
    189         HCD[i].code[len] = ''; //字符串末尾 
    190         ReverseStr(HCD[i].code); 
    191     }
    192     printf("
    *** 打印每个字符的编码 ***
    ");
    193     for(int i = 0; i <= LeafNum-1; i++)
    194         printf("%c: %s
    ", HT[i].ch, HCD[i].code);
    195 }
    196     //将一个字符串反转  
    197     void ReverseStr(char *str) {  
    198         int i, j;  
    199         char c;  
    200         for(i = 0, j = strlen(str)-1; i < j; i++, j--) {  
    201             c = str[i];  
    202             str[i] = str[j];  
    203             str[j] = c;  
    204         }
    205     }
    206 
    207 //哈夫曼编码
    208 void EncodeStr() {
    209     int len = strlen(EnterStr);
    210     printf("
    *** 编码结果 ***
    ");
    211     for(int i = 0; i <= len-1; i++) {
    212         for(int j = 0; j <= LeafNum-1; j++) {
    213             if(EnterStr[i] == HCD[j].ch)
    214                 printf("%s", HCD[j].code);
    215         }
    216     }
    217     printf("
    ");
    218 }
    219 
    220 //哈夫曼解码
    221 void DecodeHFCode() {
    222     int k = NodeNum-1; //根结点序号, 开始时一定在最后一个
    223     int len = 0, i = 0;  
    224     while(EnterCode[i]) {  
    225         if(EnterCode[i] == '0'+0)  
    226             k = HT[k].lchild;  
    227         else if(EnterCode[i] == '0'+1)  
    228             k = HT[k].rchild;  
    229         else {
    230             printf("
    错误! 密文中仅能含有1和0!
    
    ");
    231             exit(-1);
    232         }  
    233         if(HT[k].lchild == -1 && HT[k].rchild == -1) {  
    234             RealStr[len++] = HT[k].ch;
    235             k = NodeNum-1;
    236         }  
    237         i++;  
    238     }
    239     RealStr[len] = '';
    240     if(k == NodeNum-1) {     
    241         printf("
    *** 解码结果 ***
    %s
    
    ", RealStr);
    242         exit(0);
    243     }
    244     printf("
    错误! 部分密文无法解密!
    
    ");
    245     exit(-1);  
    246 }
  • 相关阅读:
    线程安全的signals
    排序
    TCMalloc : ThreadCaching Malloc
    C++箴言:争取异常安全的代码
    windows 内存泄露debug的相关函数
    分析几个驱动
    CAsyncSocket对象不能跨线程之分析 (转载)
    优化理论
    标 题: C++0x把Concept去掉了
    几个流行的http 服务器开源软件
  • 原文地址:https://www.cnblogs.com/deepcho/p/huffman-tree-node-code-decode-encode-cpp.html
Copyright © 2020-2023  润新知