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
原文地址:https://www.cnblogs.com/ygdblogs/p/5012773.html