• 数据结构实验四-赫夫曼编码


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 //////////////////////////////////////////////////////////////////////////////
      5 /*定义赫夫曼树结点的结构体变量,存放结点的权值、字符、双亲、坐孩子和右孩子*/
      6 typedef struct{
      7     int weight;
      8     char ch;                 //增加一个域用于存放该节点的字符
      9     int parent, lchild, rchild;
     10 }HTNode, *HuffmanTree;
     11 typedef char **HuffmanCode; //指向赫夫曼编码的指针
     12 //////////////////////////////////////////////////////////////////////////////
     13 /*本程序用到的函数原型*/
     14 void welcome();    //打印操作选择界面
     15 void HuffmanCoding(HuffmanTree &, char *, int *, int);//建立赫夫曼树的算法
     16 void select(HuffmanTree HT, int j, int *s1, int *s2); //从目前已建好的赫夫曼树中选择parent为0且weight最小的两个结点
     17 void Init(); //输入n个字符及其对应的权值,根据权值建立哈夫曼树
     18 void Coding(); //编码
     19 void Decoding(); //译码
     20 void Print_code(); //打印译码好的代码文件
     21 void Print_tree(); //以凹凸表形式打印哈夫曼树
     22 int Read_tree(HuffmanTree &HT); //从文件中读入赫夫曼树
     23 void find(HuffmanTree &HT, char *code, char *text, int i, int m);//译码时根据01字符串寻找相应叶子节点的递归算法
     24 void Convert_tree(unsigned char T[100][100], int s, int *i, int j);//将内存中的赫夫曼树转换成凹凸表形式的赫夫曼树
     25 HuffmanTree HT; //全局变量,指向存放赫夫曼树的存储空间
     26 int n = 0; //全局变量,存放赫夫曼树叶子结点的数目
     27 int main()
     28 {
     29     char select;
     30     while (1)
     31     {
     32         welcome();
     33         scanf("%c", &select);
     34         switch (select)
     35         {
     36         case 'i':
     37         case 'I':Init(); break;
     38         case 'c':
     39         case 'C':Coding(); break;
     40         case 'd':
     41         case 'D':Decoding(); break;
     42         case 'p':
     43         case 'P':Print_code(); break;
     44         case 't':
     45         case 'T':Print_tree(); break;
     46         case 'e':
     47         case 'E':exit(1);
     48         default:printf("Input error!
    ");
     49         }
     50         getchar();
     51     }
     52     return 0;
     53 }
     54 void welcome() //打印操作选择界面
     55 {
     56     printf("*-----------------------------------------------------*
    ");
     57     printf("|                What do you want to do?              |
    ");
     58     printf("|-----------------------------------------------------|
    ");
     59     printf("|                                                     |
    ");
     60     printf("| I--------------------------Init the Huffman tree. |
    ");
     61     printf("| C--------------------------Code your file.         |
    ");
     62     printf("| D--------------------------Decode the code.        |
    ");
     63     printf("| P--------------------------Print the codefile.     |
    ");
     64     printf("| T--------------------------Print the Huffman tree. |
    ");
     65     printf("|                                                     |
    ");
     66     printf("*-----------------------------------------------------*
    ");
     67 }
     68 //////////////////////////////////////////////////////////////////////////////////////
     69 /*初始化函数,输入n个字符及其对应的权值,根据权值建立哈夫曼树,并将其存于文件hfmtree中*/
     70 void Init()
     71 {
     72     FILE *fp;
     73     int i, n, w[52]; //w数组存放n个字符的权值
     74     char character[52]; //存放n个字符
     75     printf("
    输入字符个数 n:");
     76     scanf("%d", &n);        //输入字符集大小
     77     printf("输入%d个字符及其对应的权值:
    ", n);
     78     for (i = 0; i < n; i++)
     79     {
     80         char b = getchar();
     81         scanf("%c", &character[i]);
     82         scanf("%d", &w[i]);           //输入n个字符和对应的权值
     83     }
     84     HuffmanCoding(HT, character, w, n);    //建立赫夫曼树
     85     if ((fp = fopen("hfmtree.txt", "w")) == NULL)
     86         printf("Open file hfmtree.txt error!
    ");
     87     for (i = 1; i <= 2 * n - 1; i++)
     88     {
     89         if (fwrite(&HT[i], sizeof(HTNode), 1, fp) != 1)   //将建立的赫夫曼树存入文件hfmtree.txt中
     90             printf("File write error!
    ");
     91     }
     92     printf("
    建立赫夫曼树成功,已将其存于文件hfmtree.txt中
    ");
     93     fclose(fp);
     94 }
     95 ///////////////////////////////////////////////////////////////////////////////////
     96 //////建立赫夫曼树的算法///////////////////////////////////////////////////////////
     97 void HuffmanCoding(HuffmanTree &HT, char *character, int *w, int n)
     98 {
     99     int m, i, s1, s2;
    100     HuffmanTree p;
    101     if (n <= 1) return;
    102     m = 2 * n - 1;
    103     HT = (HuffmanTree) malloc((m + 1)*sizeof(HTNode));
    104     for (p = HT + 1, i = 1; i <= n; ++i, ++p, ++character, ++w)
    105     {
    106         p->ch = *character; 
    107         p->weight = *w; 
    108         p->parent = 0; 
    109         p->lchild = 0; 
    110         p->rchild = 0;
    111     }
    112     for (; i <= m; ++i, ++p) 
    113     { 
    114         p->ch = 0; 
    115         p->weight = 0; 
    116         p->parent = 0;
    117         p->lchild = 0;
    118         p->rchild = 0; }
    119     for (i = n + 1; i <= m; ++i)
    120     {
    121         select(HT, i - 1, &s1, &s2);
    122         HT[s1].parent = i;
    123         HT[s2].parent = i;
    124         HT[i].lchild = s1; 
    125         HT[i].rchild = s2;
    126         HT[i].weight = HT[s1].weight + HT[s2].weight;
    127     }
    128 }
    129 ///////////////////////////////////////////////////////////////////////////////
    130 /*从HT[1]到HT[j]中选择parent为0且weight最小的两个结点,用s1和s2返回其序号*/
    131 void select(HuffmanTree HT, int j, int *s1, int *s2)
    132 {
    133     int i;
    134     //找weight最小的结点
    135     for (i = 1; i <= j; i++)
    136         if (HT[i].parent == 0)
    137         {
    138             *s1 = i; 
    139             break;
    140         }
    141         for (; i <= j; i++)
    142             if ((HT[i].parent == 0) && (HT[i].weight < HT[*s1].weight))
    143                 *s1 = i;
    144         HT[*s1].parent = 1;
    145         //找weight次小的结点
    146         for (i = 1; i <= j; i++)
    147             if (HT[i].parent == 0)
    148             {
    149                 *s2 = i; break;
    150             }
    151             for (; i <= j; i++)
    152                 if ((HT[i].parent == 0) && (i != *s1) && (HT[i].weight < HT[*s2].weight))
    153                     *s2 = i;
    154 }
    155 ///////////////////////////////////////////////////////////////////////////////
    156 /*对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中*/
    157 void Coding()
    158 {
    159     FILE *fp, *fw;
    160     int i, f, c, start;
    161     char *cd;
    162     HuffmanCode HC;
    163     if (n == 0)
    164         n = Read_tree(HT);//从文件hfmtree.txt中读入赫夫曼树,返回叶子结点数
    165     /////以下程序段求赫夫曼树中各叶子节点的字符对应的的编码,并存于HC指向的空间中
    166     {
    167         HC = (HuffmanCode) malloc((n + 1)*sizeof(char*) );
    168         cd = (char *) malloc(n*sizeof(char) );
    169         cd[n - 1] = '';
    170         for (i = 1; i <= n; ++i)
    171         {
    172             start = n - 1;
    173             for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
    174                 if (HT[f].lchild == c)
    175                     cd[--start] = '0';
    176                 else cd[--start] = '1';
    177                 HC[i] = (char *) malloc((n - start)*sizeof(char) );
    178                 strcpy(HC[i], &cd[start]);
    179         }
    180         free(cd);
    181     }
    182     /////////////////////////////////////////////////////////////////////////////////////
    183     if ((fp = fopen("tobetrans.txt", "rb")) == NULL)
    184         printf("Open file tobetrans.txt error!
    ");
    185     if ((fw = fopen("codefile.txt", "wb+")) == NULL)
    186         printf("Open file codefile.txt error!
    ");
    187     char temp;
    188     fscanf(fp, "%c", &temp); //从文件读入第一个字符
    189     while (!feof(fp))
    190     {
    191         for (i = 1; i <= n; i++)
    192             if (HT[i].ch == temp) break;    //在赫夫曼树中查找字符所在的位置
    193         for (int r = 0; HC[i][r] != ''; r++) //将字符对应的编码存入文件
    194             fputc(HC[i][r], fw);
    195         fscanf(fp, "%c", &temp);        //从文件读入下一个字符
    196     }
    197     fclose(fw);
    198     fclose(fp);
    199     printf("
    对文件hfmtree.txt编码成功,结果已存入codefile.txt中。
    
    ");
    200 }
    201 
    202 /////////////////////////////////////////////////////////////////////////
    203 /*将文件codefile中的代码进行译码,结果存入文件textfile中*/
    204 void Decoding()
    205 {
    206     FILE *fp, *fw;
    207     int m, i;
    208     char *code, *text, *p;
    209     if (n == 0)
    210         n = Read_tree(HT);//从文件hfmtree.txt中读入赫夫曼树,返回叶子结点数
    211     if ((fp = fopen("codefile.txt", "rb")) == NULL)
    212         printf("Open file codefile.txt error!
    ");
    213     if ((fw = fopen("textfile.txt", "wb+")) == NULL)
    214         printf("Open file textfile.txt error!
    ");
    215     code = (char *) malloc(sizeof(char) );
    216     fscanf(fp, "%c", code);        //从文件读入一个字符
    217     for (i = 1; !feof(fp); i++)
    218     {
    219         code = (char *) realloc(code, (i + 1)*sizeof(char) ); //增加空间
    220         fscanf(fp, "%c", &code[i]);     //从文件读入下一个字符 
    221     }
    222     code[i - 1] = '';
    223     /////////到此codefile.txt文件中的字符已全部读入,存放在code数组中
    224     text = (char *) malloc(100 * sizeof(char) );
    225     p = text;
    226     m = 2 * n - 1;
    227     if (*code == '0')
    228         find(HT, code, text, HT[m].lchild, m);   //从根节点的左子树去找
    229     else
    230         find(HT, code, text, HT[m].rchild, m);   //从根节点的右子树去找
    231     for (i = 0; p[i] != ''; i++) //把译码好的字符存入文件textfile.txt中
    232         fputc(p[i], fw);
    233     fclose(fp);
    234     fclose(fw);
    235     printf("
    对codefile.txt文件译码成功,结果已存入textfile.txt文件。
    
    ");
    236 }
    237 //////////////////////////////////////////////////////////////////////////////////////////////////////
    238 /*将文件codefi1e以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件codeprint中。*/
    239 void Print_code()
    240 {
    241     FILE *fp, *fw;
    242     char temp;
    243     int i;
    244     if ((fp = fopen("codefile.txt", "rb")) == NULL)
    245         printf("Open file codefile.txt error!
    ");
    246     if ((fw = fopen("codeprint.txt", "wb+")) == NULL)
    247         printf("Open file codeprint.txt error!
    ");
    248     printf("
    文件codefi1e以紧凑格式显示如下:
    ");
    249     fscanf(fp, "%c", &temp);        //从文件读入一个字符
    250     for (i = 1; !feof(fp); i++)
    251     {
    252         printf("%c", temp);
    253         if (i % 50 == 0) printf("
    ");
    254         fputc(temp, fw);   //将该字符存入文件codeprint.txt中
    255         fscanf(fp, "%c", &temp);        //从文件读入一个字符
    256     }
    257     printf("
    
    此字符形式的编码已写入文件codeprint.txt中.
    
    ");
    258     fclose(fp);
    259     fclose(fw);
    260 }
    261 //////////////////////////////////////////////////////////////////////////////////////////////////
    262 /*将已在内存中的哈夫曼树以凹凸表形式显示在屏幕上,同时将此字符形式的哈夫曼树写入文件treeprint中。*/
    263 void Print_tree()
    264 {
    265     unsigned char T[100][100];
    266     int i, j, m = 0;
    267     FILE *fp;
    268     if (n == 0)
    269         n = Read_tree(HT);//从文件hfmtree.txt中读入赫夫曼树,返回叶子结点数
    270 
    271     Convert_tree(T, 0, &m, 2 * n - 1); //将内存中的赫夫曼树转换成凹凸表形式的树,存于数组T中
    272     if ((fp = fopen("treeprint.txt", "wb+")) == NULL)
    273         printf("Open file treeprint.txt error!
    ");
    274     printf("
    以凹凸表形式打印已建好的赫夫曼树:
    ");
    275     for (i = 1; i <= 2 * n - 1; i++)
    276     {
    277         for (j = 0; T[i][j] != 0; j++)
    278         {
    279             if (T[i][j] == ' ') { printf(" "); fputc(T[i][j], fp); }
    280             else
    281             {
    282                 printf("%d", T[i][j]); fprintf(fp, "%d
    ", T[i][j]);
    283             }
    284         }
    285         printf("
    ");
    286     }
    287     fclose(fp);
    288     printf("
    此字符形式的哈夫曼树已写入文件treeprint.txt中.
    
    ");
    289 
    290 }
    291 //////////////////////////////////////////////////////////////////////////////////
    292 /*从文件hfmtree.txt中读入赫夫曼树,返回叶子节点数*/
    293 int Read_tree(HuffmanTree &HT)
    294 {
    295     FILE *fp;
    296     int i, n;
    297     HT = (HuffmanTree) malloc(sizeof(HTNode));
    298     if ((fp = fopen("hfmtree.txt", "r")) == NULL)
    299         printf("Open file hfmtree.txt error!
    ");
    300     for (i = 1; !feof(fp); i++)
    301     {
    302         HT = (HuffmanTree) realloc(HT, (i + 1)*sizeof(HTNode)); //增加空间
    303         fread(&HT[i], sizeof(HTNode), 1, fp); //读入一个节点信息
    304     }
    305     fclose(fp);
    306     n = (i - 1) / 2;
    307     return n;
    308 }
    309 ////////////////////////////////////////////////////////////////
    310 /*译码时根据01字符串寻找相应叶子节点的递归算法*/
    311 void find(HuffmanTree &HT, char *code, char *text, int i, int m)
    312 {
    313 
    314     if (*code != '') //若译码未结束
    315     {
    316         code++;
    317         if (HT[i].lchild == 0 && HT[i].rchild == 0)   //若找到叶子节点
    318         {
    319             *text = HT[i].ch; //将叶子节点的字符存入text中
    320             text++;
    321             if ((*code == '0'))
    322                 find(HT, code, text, HT[m].lchild, m); //继续从根节点的左子树找
    323             else
    324                 find(HT, code, text, HT[m].rchild, m); //继续从根节点的右子树找
    325         }
    326         else   //如果不是叶子节点
    327             if (*code == '0')
    328                 find(HT, code, text, HT[i].lchild, m);   //从该节点的左子树去找
    329             else
    330                 find(HT, code, text, HT[i].rch
    331                 
    332                 
    333                 
    334                 
    335                 
    336                 
    337                 
    338                 
    339                 
    340                 
    341                 
    342                 
    343                 
    344                 
    345                 
    346                 
    347                 
    348                 
    349                 
    350                 
    351                 
    352                 ------------------ild, m);   //从该节点的右子树去找
    353 
    354     }
    355     else
    356         *text = ''; //译码结束
    357 }
    358 ////////////////////////////////////////////////////////////////////////
    359 /*将内存中的赫夫曼树转换成凹凸表形式的赫夫曼树*/
    360 void Convert_tree(unsigned char T[100][100], int s, int *i, int j)
    361 {
    362     int k, l;
    363     l = ++(*i);
    364     for (k = 0; k < s; k++)
    365         T[l][k] = ' ';
    366     T[l][k] = HT[j].weight;
    367     if (HT[j].lchild)
    368         Convert_tree(T, s + 1, i, HT[j].lchild);
    369     if (HT[j].rchild)
    370         Convert_tree(T, s + 1, i, HT[j].rchild);
    371     T[l][++k] = '';
    372 }
  • 相关阅读:
    linux高可用集群(HA)原理详解
    【C#/WPF】修改图像的DPI、Resolution
    【C#】图像的变形/变换/扭曲。用Emgu或YLScsFreeTransform(FreeImageTransformation)或MagickImage
    【C#】遍历List列表的同时,移除访问到的元素
    【WPF】动态设置Binding的ConverterParameter转换器参数
    【SVN/Visual Studio】清除/更换AnkhSVN的用户登录信息
    【C#】允许泛型方法<T>返回空值Null
    【C#】时间日期格式转换:long和DateTime相互转换
    【C#/WPF】ListView的MVVM例子,及禁止拖动ListView的头部Header
    【C#/WPF】保存BitmapImage数据到文件中
  • 原文地址:https://www.cnblogs.com/Zblogs/p/3440460.html
Copyright © 2020-2023  润新知