zoukankan      html  css  js  c++  java
  • huffman tree

    要求:

      对于给定的字符串构建哈夫曼树,生成 huffman 编码,并进行编码 / 译码。

    思路:

          1. 生成 huffman 树
                1> 对样本中各个字符出现次数进行统计
                2> 按统计结果以 队列 形式排列
                3> 从队列中拿出前两个生成子树,父节点大小为两节点之和
                4> 将子树再次按顺序插入队列
                5> 重复 3 4 操作,至最后只有一个根节点
          2. 生成 huffman 编码
                1> 以结构体存放字符(变量)及其 huffman 编码(数组)
                2> 向左为 0 ,向右为 1 ,到指针指向 NULL

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include "huffman.h"
     4 
     5 int main()
     6 {
     7     htTree *codeTree = buildTree("I am yan guo dong!");            // 创建huffman树 通过对字符出现的次数进行统计 
     8     
     9     hlTable *codeTable = buildTable(codeTree);                    // huffman树 -> huffman编码 按次数进行 huffman 编码 
    10     
    11     encode(codeTable, "I am yan guo dong!");                        // 对字符进行编码 
    12     
    13     decode(codeTree, "0011111000111");                            // 对编码进行解码 
    14     
    15     return 0;
    16 }
    17 
    18 
    19 /* 
    20     1. 生成 huffman 树
    21             1> 对样本中各个字符出现次数进行统计
    22             2> 按统计结果以 队列 形式排列 
    23             3> 从队列中拿出前两个生成子树,父节点大小为两节点之和
    24             4> 将子树再次按顺序插入队列
    25             5> 重复 3 4 操作,至最后只有一个根节点 
    26     2. 生成 huffman 编码 
    27             1> 以结构体存放字符(变量)及其 huffman 编码(数组) 
    28             2> 向左为 0 ,向右为 1 ,到指针指向 NULL 
    29 */ 
    main.cpp
     1 #pragma once
     2 #ifndef _PQUEUE_H
     3 #define _PQUEUE_H
     4 
     5 #include "huffman.h"
     6 
     7 #define TYPE htNode *
     8 
     9 #define MAX_SZ 256
    10 
    11 typedef struct _pQueueNode        // 队列的节点 
    12 {
    13     TYPE val;                    // 指向一个树的指针 
    14     unsigned int priority;        // 优先级(非负) 即该字符出现的次数 
    15     struct _pQueueNode *next;    // 指向下一个节点 
    16 } pQueueNode;
    17 
    18 typedef struct _pQueue            // 指向队列的头指针类型 
    19 {
    20     unsigned int size;            // 队列的长度 
    21     pQueueNode *first;            // 队列的头指针 
    22 } pQueue;
    23 
    24 // 队列初始化 传入队列头结点的地址
    25 void initPQueue(pQueue **queue);
    26 // 将节点插入队列 传入(指针头结点的地址 ,待插入树的节点的指针 ,优先级即字符出现的次数 )
    27 void addPQueue(pQueue **queue, TYPE val, unsigned int priority);
    28 // TYPE是树节点的类型     从队列中获取树节点
    29 TYPE getPQueue(pQueue **queue);
    30 
    31 #endif
    queue.h
     1 #pragma once                // 防止被重复定义 
     2 #ifndef _HUFFMAN_H            // 如果没有定义 ,已经定义则跳过 
     3 #define _HUFFMAN_H            // 定义 
     4 
     5 typedef struct _htNode                // 树的节点 
     6 {
     7     char symbol;                    // 存放的是字符 
     8     struct _htNode *left, *right;
     9 } htNode;
    10 
    11 typedef struct _htTree        
    12 {
    13     htNode *root;                     // 树的根节点 
    14 } htTree;
    15 
    16 typedef struct _hlNode                // 链表节点 
    17 {
    18     char symbol;                    // 存放需编码的字符 
    19     char *code;                        // 字符指针,即字符串,存放huffman编码 
    20     struct _hlNode *next;            // 指向下一个节点 
    21 }hlNode;
    22 
    23 typedef struct _hlTable
    24 {
    25     hlNode *first;
    26     hlNode *last;
    27 }hlTable;
    28 
    29 htTree *buildTree(char *inputString);
    30 hlTable *buildTable(htTree *huffmanTree);
    31 void encode(hlTable *table, char *stringToEncode);
    32 void decode(htTree *tree, char *stringToDecode);
    33 
    34 #endif
    huffman.h
     1 #include "queue.h"
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 
     5 void initPQueue(pQueue **queue)                // 队列初始化 传入队列头结点的地址
     6 {
     7     (*queue) = (pQueue *) malloc(sizeof(pQueue));        
     8     (*queue)->first = NULL;
     9     (*queue)->size = 0;
    10 }
    11 
    12 //                 将节点插入队列 
    13 //        传入(指针头结点的地址 ,待插入树的节点的指针 ,优先级即字符出现的次数 ) 
    14 void addPQueue(pQueue **queue, TYPE val, unsigned int priority)
    15 {
    16     if((*queue)->size == MAX_SZ)            // MAX_SZ = 256  判断队列是否已满 
    17     {
    18         printf("
    Queue is full.
    ");
    19         return;
    20     }
    21     
    22     pQueueNode *aux = (pQueueNode *) malloc(sizeof(pQueueNode));        // 新建节点内存 
    23     aux->priority = priority;
    24     aux->val = val;
    25     
    26     if((*queue)->size == 0 || (*queue)->first == NULL)                    // 插入的为第一个节点
    27     {
    28         aux->next = NULL;
    29         (*queue)->first = aux;
    30         (*queue)->size = 1;
    31     }
    32     else
    33     {
    34         if(priority <= (*queue)->first->priority)            // 整个队列按字符出现的次数进行前后排序 
    35         {                                                    // 对将插入的队列节点优先级进行判断,排序 
    36             aux->next = (*queue)->first;
    37             (*queue)->first = aux;
    38             (*queue)->size++;
    39             return;
    40         }
    41         else
    42         {
    43             pQueueNode *iterator = (*queue)->first;            // 临时变量 ,等于第一个节点  
    44             while(iterator->next!=NULL)                        // 遍历整个队列,进行判断排序 
    45             {
    46                 if(priority <= iterator->next->priority)
    47                 {
    48                     aux->next = iterator->next;
    49                     iterator->next = aux;
    50                     (*queue)->size++;
    51                     return ;
    52                 }
    53                 iterator = iterator->next;
    54             }
    55             
    56             if(iterator->next == NULL)                // 当待插入节点为队列中最大的一个,即该节点位于队列最后 
    57             {
    58                 aux->next = NULL;
    59                 iterator->next = aux;
    60                 (*queue)->size++;
    61                 return;
    62             }
    63         }
    64     }
    65 }
    66 
    67 // TYPE是树节点的类型 
    68 TYPE getPQueue(pQueue **queue)                // 从队列中获取数据 
    69 {
    70     TYPE returnValue;                        // 返回的节点数据 (指针类型) 
    71     
    72     if((*queue)->size > 0)                    // 将传入队列节点的下一个队列节点中指向的树节点返回 
    73     {
    74         returnValue = (*queue)->first->val;
    75                                                         // 执行删除队列节点操作 
    76         (*queue)->first = (*queue)->first->next;        // 队列指针指向下一个队列节点 
    77         (*queue)->size--;                                // 队列长度减一 
    78     }
    79     else
    80     {
    81         printf("
    Queue is empty.
    ");
    82     }
    83     return returnValue;                        // 将指向树节点的指针返回 
    84 }
    queue.cpp
      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #include "huffman.h"
      6 #include "queue.h"
      7 
      8 // 从 huffman树 根节点开始进行 huffman编码 
      9 // 
     10 void traverseTree(htNode *treeNode, hlTable **table, int k, char code[256])
     11 {
     12     if(treeNode->left == NULL && treeNode->right == NULL)        // 没有左右孩子 为叶子节点 
     13     {
     14     
     15         code[k] = '';
     16         hlNode *aux = (hlNode *)malloc(sizeof(hlNode));
     17         aux->code = (char *)malloc(sizeof(char)*(strlen(code)+1));
     18         strcpy(aux->code, code);
     19         aux->symbol = treeNode->symbol;
     20         aux->next = NULL;
     21     
     22         if((*table)->first == NULL)
     23         {
     24             (*table)->first = aux;
     25             (*table)->last = aux;
     26         }
     27         else
     28         {
     29             (*table)->last->next = aux;
     30             (*table)->last = aux;
     31         }
     32     }
     33     
     34     if(treeNode->left != NULL)                // 递归调用 
     35     {
     36         code[k] = '0';
     37         traverseTree(treeNode->left, table, k+1, code);
     38     }
     39     
     40     if(treeNode->right != NULL)
     41     {
     42         code[k] = '1';
     43         traverseTree(treeNode->right, table, k+1, code);
     44     }
     45 }
     46 
     47 hlTable *buildTable(htTree *huffmanTree)
     48 {
     49     hlTable *table = (hlTable *)malloc(sizeof(hlTable));
     50     table->first = NULL;
     51     table->last = NULL;
     52     
     53     char code[256];                // 编码存放数组  
     54     int k = 0;                    // 当前索引 huffman树 的层数 
     55     
     56         // 传入  huffman树的根节点,链表指针,层数,编码数组 
     57     traverseTree(huffmanTree->root, &table, k, code);
     58     return table;
     59 }
     60 
     61 htTree *buildTree(char *inputString)            // 创建huffman树 
     62 {
     63     int *probability = (int *)malloc(sizeof(int)*256);        // 存储每个字符出现次数的数组 
     64     
     65     // 初始化
     66     for(int i = 0; i < 256; i++)
     67     {
     68         probability[i] = 0;                // 记录每个字符出现的次数 
     69     }
     70     
     71     // 统计待编码的字符串各个字符出现的次数 
     72     for(int j = 0; inputString[j] != ''; j++)
     73     {
     74         probability[(unsigned char)inputString[j]]++;
     75     }
     76     
     77     pQueue *huffmanQueue;                // pQueue队列的头节点
     78     initPQueue(&huffmanQueue);            // 对队列进行初始化 传入指向地址的指针的地址 
     79     
     80     // 填充对列 
     81     for(int k = 0; k < 256; k++)
     82     {
     83         if(probability[k] != 0)            // 存在ASCII码为 k 的字符 
     84         {
     85             htNode *aux = (htNode *)malloc(sizeof(htNode));            // 新建树的节点 
     86             aux->left = NULL;
     87             aux->right = NULL;
     88             aux->symbol = (char) k;
     89             
     90             addPQueue(&huffmanQueue, aux, probability[k]);            // 将节点插入队列 
     91         } 
     92     }
     93     
     94     free(probability);            // 将数组存储空间释放 
     95     
     96     // 生成 huffman 树  
     97     while(huffmanQueue->size != 1)            // 将所有树节点构造huffman树,让最后一个节点为根节点 
     98     {
     99         int priority = huffmanQueue->first->priority;                // 将两个最小的字符出现次数相加 
    100         priority += huffmanQueue->first->next->priority;
    101         
    102         htNode *left = getPQueue(&huffmanQueue);                    // 将最小两个树节点作为子树的左右孩子 
    103         htNode *right = getPQueue(&huffmanQueue);
    104         
    105         htNode *newNode = (htNode *)malloc(sizeof(htNode));            // 创建两节点的父节点 
    106         newNode->left = left;
    107         newNode->right = right;
    108         
    109         addPQueue(&huffmanQueue, newNode, priority);                // 将父节点再次加入队列, 
    110     } 
    111     
    112     htTree *tree = (htTree *)malloc(sizeof(htTree));                 // 一个指向树的节点的指针 
    113     
    114     tree->root = getPQueue(&huffmanQueue);                            // 指向根节点 
    115     
    116     return tree;
    117 }
    118 
    119 void encode(hlTable *table, char *stringToEncode)                // 编码 
    120 {
    121     hlNode *traversal;
    122     
    123     printf("Encoding.............
    
    Input string : 
    %s
    
    Encodeed string : 
    ", stringToEncode);
    124     
    125     for(int i = 0; stringToEncode[i] != ''; i++)
    126     {
    127         traversal = table->first;
    128         while(traversal->symbol != stringToEncode[i])
    129             traversal = traversal->next;
    130         printf("%s", traversal->code);
    131     }
    132     
    133     printf("
    ");
    134 }
    135 
    136 // 解码 
    137 void decode(htTree *tree, char *stringToDecode)
    138 {
    139     htNode *traversal;
    140     traversal = tree->root;
    141     
    142     printf("Encoding.............
    
    Input string : 
    %s
    
    Decodeed string : 
    ", stringToDecode);
    143     
    144     for(int i = 0; stringToDecode[i] != ''; i++)
    145     {
    146         if(stringToDecode[i])
    147         {
    148             if(!traversal->right)
    149             {
    150                 printf("%c", traversal->symbol);
    151                 traversal = tree->root;
    152             }
    153             else
    154                 traversal = traversal->right;
    155         }    
    156         else{
    157             if(!traversal->left)
    158             {
    159                 printf("%c", traversal->symbol);
    160                 traversal = tree->root;
    161             }
    162             traversal = traversal->left;
    163         }
    164     }
    165 }
    huffman.cpp
    转载请注明出处:http://www.cnblogs.com/ygdblogs
  • 相关阅读:
    QML vs WEB
    《TO C产品经理进阶》
    《TO B产品设计标准化》
    《多元思维模型》跨学科及其核心思维模型
    产品经理审美训练
    Aria2多线程轻量级批量下载利器
    正则表达式
    如何开发一个用户脚本系列教程
    Aria2自动下载
    助贷
  • 原文地址:https://www.cnblogs.com/ygdblogs/p/5012773.html
Copyright © 2011-2022 走看看