哈夫曼编码其实就是一种数据压缩的方法,他会根据数据出现的频率来进行重新编码,减少空间大小,比如一段文章中 字符 ‘A’ 出现的频率非常的多,大家都知道一个字符占用八个字节,这时候我们用 二进制1 来代表 字符 ‘A’,那这段文章中所有的 字符‘A’岂不是缩小八倍吗,这意味着出现八次 ‘A’ 才跟原来一个‘A’占用的空间一样大
我使用优先队列和二叉树来完成哈夫曼树的实现,
队列的相关知识我就不将了,如果你按照顺序学习的话,队列应该已经学会了
huffmanTree.h 代码如下:
#pragma once
#define MAXSIZE 10
//树节点内容
typedef struct _Bnode {
char value; //字符
int weight; //权值,根据权值的大小来决定出现的频率
_Bnode* lchild;
_Bnode* rchild;
_Bnode* parent; //这个节点是用来记录两个权值的和
}Bnode;
typedef Bnode* BnodePtr;
//队列节点内容
typedef struct _QNode {
int priority;
BnodePtr data;
_QNode* next;
}QNode;
typedef QNode* QNodePtr;
//队列指针
typedef struct _Queue {
QNodePtr front; //队列的头
QNodePtr rear; //队列的尾
int length;
}Queue;
//初始化队列
bool initQueue(Queue* LQ);
//插入队列
bool enterQueue(Queue* LQ, Bnode* node, int priority);
//出队列
bool escapeQueue(Queue* LQ, Bnode*& node);
//判断空
bool isEmpty(Queue* LQ);
//判断满
bool isFull(Queue* LQ);
//清空队列
void destroyQueue(Queue* LQ);
//打印队列信息
void printQueue(Queue* LQ);
//实现哈夫曼树的创建
void huffmanTree(Bnode*& huff, int n); /*这里用了指针引用,是因为我需要把原来的指针改
变一下指向的目标,(这里用二级指针也可以)*/
huffmanTree.cpp 实现代码如下:
#include "HuffmanTree.h"
#include <iostream>
using namespace std;
//初始化队列
bool initQueue(Queue* LQ) {
if (!LQ)return false;
LQ->front = LQ->rear = NULL;
LQ->length = 0;
return true;
}
//插入队列
bool enterQueue(Queue* LQ, Bnode* node, int priority) {
if (!LQ)return false;
QNode* qNode = new QNode;
if (!qNode)return false;
qNode->data = node;
qNode->next = NULL;
qNode->priority = priority;
if (LQ->front == NULL && LQ->rear == NULL) {
LQ->front = qNode;
LQ->rear = qNode;
LQ->length++;
return true;
}
//下面这段入队顺序可以不一样,因为是优先队列,他会对优先级进行出队,而不是常规队列
//==================================
qNode->next = LQ->front;
LQ->front = qNode;
//==================================
LQ->length++;
return true;
}
//出队列
bool escapeQueue(Queue* LQ, Bnode*& node) {
if (!LQ)return false;
if (isFull(LQ))return false;
QNode** pre = NULL, *pre_node = NULL;
QNode* last = NULL, *tmp = NULL;
pre = &LQ->front;
last = LQ->front;
tmp = last->next;
//在这个循环中一直进行优先级的判断
while (tmp)
{
if (tmp->priority < (*pre)->priority) {
pre = &last->next;
pre_node = last;
}
last = tmp; //这里也可以写 last = last->next; 主要功能就是跳到下一个节点
tmp = tmp->next;
}
tmp = *pre;
node = (*pre)->data;
(*pre) = (*pre)->next; /*指向后后一个节点,就是删除节点的前一个节点指向了删除节点的后一
个节点*/
delete tmp;
LQ->length--;
//两种出队列特殊的情况
//只有一个节点,并且出队列了
if (LQ->length == 0) {
LQ->rear = NULL; /*这里没有让front = NULL,是因为如果该队列为空,那么在上边的
(*pre)中就会把front给改变指向了*/
}
//出队节点是最后一个节点
if (pre_node && pre_node->next == NULL) {
LQ->rear = pre_node;
}
return true;
}
//判断空
bool isEmpty(Queue* LQ) {
if (LQ->length == 0) {
return true;
}
else {
return false;
}
}
//判断满
bool isFull(Queue* LQ) {
if (LQ->length == MAXSIZE)return true;
return false;
}
//清空队列
void destroyQueue(Queue* LQ) {
if (!LQ) {
cout << "空指针" << endl;
return;
}
while (LQ->front)
{
QNode* node = LQ->front;
LQ->front = LQ->front->next;
delete node;
}
LQ->front = NULL;
LQ->length = 0;
LQ->rear = NULL;
}
//打印队列信息
void printQueue(Queue* LQ) {
if (!LQ)return;
QNode* tmp = LQ->front;
while (tmp)
{
cout << "-" << tmp->data->value << "-" << " ";
tmp = tmp->next;
}
cout << endl;
}
//实现哈夫曼树的创建
void huffmanTree(Bnode*& huff, int n) {
Queue* LQ = new Queue;
initQueue(LQ);
if (!LQ)return;
for (int i = 0; i < n; ++i) {
Bnode* node = new Bnode;
//这次输入的两个值都会记录到value和weight中
cout << "请输入第 " << i + 1 << " 个字符和出现的次数:" << endl;
cin >> node->value;
cin >> node->weight;
node->parent = NULL;
node->lchild = NULL;
node->rchild = NULL;
cin.get(); //把回车键接受
enterQueue(LQ, node,node->weight);
}
printQueue(LQ);
//下面就是哈夫曼的实现
do
{
Bnode* node1;
Bnode* node2;
if (!isEmpty(LQ)) {
escapeQueue(LQ, node1);
printf("第一个出队列的数:%c, 优先级: %d\n", node1->value,
node1->weight);
}
else {
break;
}
if (!isEmpty(LQ)) {
escapeQueue(LQ, node2);
printf("第二个出队列的数:%c, 优先级: %d\n", node2->value,
node2->weight);
Bnode* node3 = new Bnode;
node3->lchild = node1;
node3->rchild = node2;
node1->parent = node3;
node2->parent = node3;
node3->value = ' ';
node3->weight = node1->weight + node2->weight;
enterQueue(LQ, node3, node3->weight);
}
else {
huff = node1;
break;
}
} while (1);
}
main.cpp 代码如下:
#include <iostream>
#include "HuffmanTree.h"
using namespace std;
void preTree(Bnode* root) {
if (root == NULL)return;
cout << root->value << " ";
preTree(root->lchild);
preTree(root->rchild);
}
int main()
{
Bnode* root = new Bnode;
huffmanTree(root, 7);
preTree(root);
return 0;
}