实现方案:
1. 建立哈夫曼树
(1)统计各个字符出现次数,按次数从小到大的顺序生成队列;
(2)每次获取队列前两个节点(即队列中字符出现次数最少的两个),同时队头前移两位,将它们的字符出现次数相加,得到一个新节点,插入到队列合适位置;
(3)当队列中仅剩一个节点时,哈夫曼树构造完毕,该节点即为树的根节点。
2. 建立哈夫曼编码表
(1)从哈夫曼树根开始遍历,遍历结束的同时编码表也构造完成,整个过程用递归实现,注意结束条件为遍历到叶子节点;
(2)如果当时节点的左孩子不为空,则code[k]='0',递归遍历其左子树;
(3)如果当时节点的右孩子不为空,则code[k]='1',递归遍历其右子树;
(4)如果当时节点为叶子,则code[k]=' ',构造新的编码表节点,并将其插入编码表。
3. 将字符串和哈夫曼编码互换,测试
代码如下,时常翻看,细细揣摩,大有裨益:
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_SZ 256 #define TYPE htNode * // 哈夫曼树节点 typedef struct htNode{ char symbol; struct htNode *left; struct htNode *right; }htNode; // 哈夫曼树 typedef struct htTree{ htNode *root; }htTree; // 队列节点 typedef struct pQueueNode{ TYPE val; unsigned int priority; struct pQueueNode *next; }pQueueNode; // 队列 typedef struct pQueue{ unsigned int size; // 队列长度 pQueueNode *first; // 头指针 }pQueue; // 字符编码节点 typedef struct hlNode{ char symbol; char *code; struct hlNode *next; }hlNode; // 字符编码表 typedef struct hlTable{ hlNode *first; hlNode *last; }hlTable; // 初始化哈夫曼队列 void initpQueue(pQueue **q) { (*q) = (pQueue *)malloc(sizeof(pQueue)); (*q)->first = NULL; (*q)->size = 0; return; } // 插入队列 void addpQueue(pQueue **q,TYPE val,unsigned int priority) { if ((*q)->size == MAX_SZ){ printf("Queue is full. "); return; } pQueueNode *aux = (pQueueNode *)malloc(sizeof(pQueueNode)); aux->priority = priority; aux->val = val; if ((*q)->first == NULL || (*q)->size == 0){ // 队列为空 aux->next = NULL; (*q)->first = aux; (*q)->size = 1; } else{ // 小于第一个节点 if (priority <= (*q)->first->priority){ aux->next = (*q)->first; (*q)->first = aux; (*q)->size++; return; } // 迭代 else{ pQueueNode *iterator = (*q)->first; while(iterator->next != NULL){ if (priority <= iterator->next->priority){ aux->next = iterator->next; iterator->next = aux; (*q)->size++; return; } iterator = iterator->next; } // 比队列里所有的都大 if (iterator->next == NULL){ aux->next = NULL; iterator->next = aux; (*q)->size++; return; } } } } // 从队列中获取节点 TYPE getpQueue(pQueue **q) { TYPE returnVal; if ((*q)->size > 0){ returnVal = (*q)->first->val; (*q)->first = (*q)->first->next; (*q)->size --; } else{ printf("Queue is empty. "); } return returnVal; } htTree *buildTree(char *inputString) { // 256个指针记录256个ASCII码出现的次数 int *probability = (int *)malloc(sizeof(int)*256); // 初始化 for (int i=0; i<256; i++){ probability[i] = 0; } // 统计待编码的字符串各个字符出现的次数 for (int j=0; inputString[j]!='