关于赫夫曼编码和赫夫曼树的相关知识可參考之前两篇文章(由二叉树构造赫夫曼树、赫夫曼编码)。
本文介绍还有一种构建赫夫曼树的方式,採用优先队列.
1.首先我们须要统计不同字符出现的次数。一个字符出现的次数越多,说明其优先级越高,其赫夫曼编码应该越短;
2.将待编码的字符(即带权节点)存入优先级队列,优先级即字符出现的次数;
3.不断迭代队列,直到队列中剩下一个元素(即根节点)。每次从队列中取出两个优先级最小的元素(优先级队列中的元素是依照节点优先级顺序排列的),然后生成一个新的赫夫曼树节点,节点左右孩子分别指向这两个元素,节点权值为这两个元素权值之和。将新节点插入队列;
4.依据赫夫曼树生成赫夫曼编码表。递归遍历赫夫曼树,对每一个叶子节点进行编码(左0右1);
5.编码过程即对每一个字符查编码表的过程;
6.解码过程即依据编码串訪问赫夫曼树的过程.
实现:
/*****************************************************
赫夫曼编码优先队列版
by Rowandjj
2014/6/17
*****************************************************/
#include<iostream>
using namespace std;
typedef struct _HTNODE_//赫夫曼树节点的存储结构
{
char symbol;//符号(ASC码值)
struct _HTNODE_ *left;//左孩子
struct _HTNODE_ *right;//右孩子
}HtNode;
typedef struct _HTREE_//赫夫曼树
{
HtNode *root;
}HTree;
typedef struct _HLNODE_//赫夫曼码表节点
{
char symbol;//ASC码值
char *code;//相应的编码
struct _HLNODE_ *next;
}HlNode;
typedef struct _HLTABLE_//赫夫曼码表(以单链表形式存储不同ASC码及与之相应的编码表)
{
HlNode *first;
HlNode *last;
}HlTable;
//--------------------------------------------------------
#define MAX_SZ 256//队列最大长度
#define TYPE HtNode*//优先队列的节点定义
typedef struct _PQUEUENODE_//队列节点定义
{
TYPE val;//节点值
unsigned int priority;//优先级
struct _PQUEUENODE_ *next;
}pQueueNode;
typedef struct _PQUEUE_//优先队列定义
{
unsigned int size;//队列长度
pQueueNode *first;//首节点
}pQueue;
//-----------优先队列操作定义------------------------------
void InitQueue(pQueue **queue);//队列初始化
void AddQueue(pQueue **queue,TYPE val,unsigned int priority);//将一个带优先级的节点插入队列
TYPE GetQueue(pQueue **queue);//队列节点依照优先级顺序出队
void TraverseQueue(pQueue *queue);//遍历队列
//-----------赫夫曼编码操作定义----------------------------
HTree* BuildTree(char *inputString);//创建赫夫曼树
HlTable* BuildTable(HTree *huffmanTree);//构建赫夫曼码表(出现频率最高的ASC码将使用最短的编码)
void encode(HlTable *table,char *stringToEncode);//编码
void decode(HTree *tree,char *stringToDecode);//解码
void TraverseTable(HlTable *table);//遍历赫夫曼编码表
//---------------------------------------------------------
void InitQueue(pQueue **queue)
{
*queue = (pQueue *)malloc(sizeof(pQueue));
(*queue)->first = NULL;
(*queue)->size = 0;
}
void AddQueue(pQueue **queue,TYPE val,unsigned int priority)
{
if((*queue)->size == MAX_SZ)
{
cout<<"queue is full!";
return;
}
pQueueNode *aux = (pQueueNode*)malloc(sizeof(pQueueNode));
aux->priority = priority;
aux->val = val;
aux->next = NULL;
if((*queue)->first == NULL)//生成队列首节点
{
(*queue)->first = aux;
(*queue)->size++;
}else
{
if(priority <= (*queue)->first->priority)//插到首节点位置
{
aux->next = (*queue)->first;
(*queue)->first = aux;
(*queue)->size++;
}else//遍历队列插到合适的位置
{
pQueueNode *iterator = (*queue)->first;
while(iterator->next != NULL && priority > iterator->next->priority)
{
iterator = iterator->next;
}
aux->next = iterator->next;
iterator->next = aux;
(*queue)->size++;
}
}
}
TYPE GetQueue(pQueue **queue)
{
TYPE returnVal = NULL;
if ((*queue)->size > 0)
{
pQueueNode *nodeToDel = (*queue)->first;
(*queue)->first = (*queue)->first->next;
returnVal = nodeToDel->val;
free(nodeToDel);
(*queue)->size--;
}else
{
cout<<"queue is empty"<<endl;
}
return returnVal;
}
//-------------------------------------------------------------
HTree* BuildTree(char *inputString)
{
//统计字符出现次数
int *probability = (int*)malloc(sizeof(int)*256);
int i;
for(i = 0; i < 256;i++)
{
probability[i] = 0;
}
for(i = 0; inputString[i] != '