哈夫曼树(霍夫曼树)又称为最优树.
1、路径和路径长度
在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
2、结点的权及带权路径长度
哈夫曼树(3)
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
3、树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#define TYPE htNode *
#define MAX_SZ 256
//队列树节点
typedef struct _htNode
{
char symbol;
struct _htNode* left;
struct _htNode *right;
} htNode;
//树根
typedef struct _htTree
{
htNode* root;
} htTree;
//树节点
typedef struct _hlNode
{
char symbol; //索引字符 'a'
char* code; //编码 010101
struct _hlNode* next; //下一个
}hlNode;
typedef struct _hlTable
{
hlNode* first; //指向第一个
hlNode* last; //指向下面的每一个
} hlTable;
//队列节点
typedef struct _pQueueNode
{
TYPE val;
unsigned int priority;
struct _pQueueNode* next;
}pQueueNode;
//
typedef struct _pQueue
{
unsigned int size; //队列的长度;当队列剩下一个元素时就是一个哈夫曼树
pQueueNode * first;
}pQueue;
//初始化队列
void initPQueue(pQueue** queue)
{
(*queue) = (pQueue*)malloc(sizeof(pQueue));
(*queue)->first = NULL;
(*queue)->size = 0 ;
}
//填充队列
void addPQueue(pQueue** queue, TYPE val, unsigned priority)
{
if ((*queue)->size == MAX_SZ)
{
printf("\n Queue is full\n");
return;
}
pQueueNode * aux = (pQueueNode*)malloc(sizeof(pQueueNode));
aux->priority = priority;
aux->val = val;
if ((*queue)->size == 0 || (*queue)->first == NULL)
{
//空队列
aux->next = NULL;
(*queue)->first = aux;
(*queue)->size++;
}
else
{
if (priority <= (*queue)->first->priority)
{
aux->next = (*queue)->first;
(*queue)->first = aux;
(*queue)->size++;
}
else
{
pQueueNode* iterater = (*queue)->first;
//迭代器
while (iterater->next != NULL)
{
if (priority <= iterater->next ->priority)
{
aux->next = iterater->next;
iterater->next = aux;
(*queue)->size++;
return;
}
//一直寻找更小的节点
iterater = iterater->next;
}
//超过最大的
if (iterater->next == NULL)
{
aux->next = NULL;
iterater->next = aux;
(*queue)->size++;
return;
}
}
}
}
//获取树节点
TYPE getPQueue(pQueue** queue)
{
TYPE returnValue = NULL;
if ((*queue)->size > 0)
{
returnValue = (*queue)->first->val;
(*queue)->first = (*queue)->first->next;
(*queue)->size--;
}
else
{
printf("\pQueue is empty \n");
}
return returnValue;
}
htTree * builfTree(char *inputString )
{
int* probability = (int*)malloc(sizeof(int) * 256);
//初始化
for (int i = 0; i < 256; i++)
{
probability[i] = 0;
}
//统计待编码的字符串各个字符出现的次数
for (int j = 0;inputString[j] != '\0'; j++)
{
//如穿进去的是I ==73 ==> probability[73]++
probability[(unsigned char)inputString[j]]++;
}
//pQueue队列的头指针
pQueue* huffmanQueue;
//初始化队列
initPQueue(&huffmanQueue);
//填充队列
for (int k = 0 ; k < 256; k++)
{
if (probability[k] != 0)
{
htNode* aux = (htNode*)malloc(sizeof(htNode));
aux->left = NULL;
aux->right = NULL;
aux->symbol = (char)k;
addPQueue(&huffmanQueue, aux, probability[k]);
}
}
free(probability);
//生成一颗哈夫曼树
while (huffmanQueue->size != 1)
{
//新节点的权
int prority = huffmanQueue->first->priority;
//两个节点之和
prority += huffmanQueue->first->next->priority;
htNode* left = getPQueue(&huffmanQueue);
htNode* right = getPQueue(&huffmanQueue);
htNode* newNode = (htNode*)malloc(sizeof(htNode));
newNode->left = left;
newNode->right = right;
addPQueue(&huffmanQueue, newNode, prority);
}
//根节点huffmanQueue->size = 1 时只有一个节点
htTree* tree = (htTree*)malloc(sizeof(htTree));
tree->root = getPQueue(&huffmanQueue);
return tree;
}
void traverseTree(htNode* treeNode, hlTable** table, int k, char code[256])
{
//叶子
if (treeNode->left == NULL && treeNode->right == NULL)
{
code[k] = '\0';
hlNode* aux = (hlNode*)malloc(sizeof(hlNode));
int len = strlen(code) + 1;
aux->code = (char*)malloc(sizeof(char) * len);
//errno_t strcpy_s(char *restrict dest, rsize_t destsz, const char *restrict src);
strcpy_s(aux->code,len, code);
aux->symbol = treeNode->symbol;
aux->next = NULL;
if ((*table)->first == NULL)
{
//只有一个节点first 、last都指向aux
(*table)->first = aux;
(*table)->last = aux;
}
else
{
//已有节点
(*table)->last->next = aux;
(*table)->last = aux;
}
}
//分支
if (treeNode->left != NULL)
{
code[k] = '0';
traverseTree(treeNode->left, table, k + 1, code);
}
if (treeNode->right != NULL)
{
code[k] = '1';
traverseTree(treeNode->right, table, k + 1, code);
}
}
hlTable* buildTable(htTree* huffmanTree)
{
hlTable *table = (hlTable*)malloc(sizeof(hlTable));
table->first = NULL;
table->last = NULL;
char code[256];
int k = 0; //往下走一级加一 位于第几层
//填充编码
traverseTree(huffmanTree->root, &table, k, code);
return table;
}
void encode(hlTable* table, char* stringToEncode)
{
hlNode* traversal;
// printf("Encode......\n\nInput string:\n%s\n\nEncode string:\n", stringToEncode);
printf("Encode......\n\nInput string:\n%s\n\nEncode string:\n", stringToEncode);
for (int i = 0;stringToEncode[i] != '\0'; i++)
{
traversal = table->first;
while (traversal->symbol != stringToEncode[i]) //地址异常
{
traversal = traversal->next;
}
printf("%s\t", traversal->code);
}
printf("\n");
}
void decode(htTree* tree, char* stringToDecode)
{
htNode* traversal = tree->root;
printf("\n\n");
printf("Encode......\n\n输入的编码:\n%s\n\n解码后:\n", stringToDecode);
for (int i = 0; stringToDecode != '\0'; i++)
{
if (traversal->left == NULL && traversal->right == NULL)
{
printf("%c", traversal->symbol);
traversal = tree->root;
}
if (stringToDecode[i] == '0')
{
traversal = traversal->left;
}
if (stringToDecode[i] == '1')
{
traversal = traversal->right;
}
if (stringToDecode[i] != '0' && stringToDecode[i] != '1')
{
//printf("\nThe input string is not coded correctle!\n");
printf("\n\n");
return;
}
}
if (traversal->left == NULL && traversal->right == NULL)
{
printf("NULL");
}
}
int main()
{
char str[100] = "这是一个哈夫曼树 huffmanTree ,Very well done !!";
char str2[400] = "1100101111011110111000011001111011011010011111111011111100011010111110011000111100111101111110100101111101000000100011011101011010011010111001001101110001010010110011001010101010010101101100000000100101100101001001101110001000100";
htTree* codeTree = builfTree(str);
hlTable* codeTable = buildTable(codeTree);
encode(codeTable,str);
decode(codeTree,str2 );
return 0;
}