以下代码时以数据结构预算法设计课本标准而来,是以c语言为基础写的。当然改进的话可以用优先队列来实现最小值的查找。
哈夫曼树和哈夫曼编码的意义在于将字符串等用二进制数来代替(也可以理解为加密的过程),代替后的二进制数最短且可以翻译为原字符串(解密)。哈夫曼的内在原理可以查阅其他文本资料,在这里我就不加以赘述了。
整体代码实现(基础c):
#include<iostream>
#include<climits>
#define K 100
using namespace std;
typedef struct{//哈夫曼树
char data; //字符
int weight; //对应权值
int parent,lchild,rchild;
}HTNode;
typedef struct{ //哈夫曼编码
char cd[K]; //字符对应的哈夫曼编码
int start; //cd[]的起始位置
}HCode;
void CreathufTree(HTNode ht[],int n){ //哈夫曼数的创建
int lnode,rnode,min1,min2; //lnode和rnode记录左右子节点,min1和min2用来寻找最小的两个数
for(int i=0;i<2*n-1;i++) //初始化,将所有的节点都设置为单根树,n个结点对应2*n-1个结点
ht[i].parent=ht[i].lchild=ht[i].rchild=-1; //双亲、左、右都没有
for(int i=n;i<2*n-1;i++){ //创建
lnode=rnode=-1; //开始记录左、右树
min1=min2=INT_MAX; //记录最小值
for(int k=0;k<i;k++){ //从i之前的所有的子树权值取最小的两个
if(ht[k].parent==-1){
if(ht[k].weight<min1){ //每次循环先比较min1,找到最小的,在比较min2
min2=min1; rnode=lnode; min2记录min1的前一个值
min1=ht[k].weight; lnode=k;
}else if(ht[k].weight<min2){ //找到倒数第二小的
rnode=k; min2=ht[k].weight;
}
}
}
ht[i].lchild=lnode; ht[i].rchild=rnode; //处理双亲
ht[i].weight=ht[lnode].weight+ht[rnode].weight;
ht[lnode].parent=i; ht[rnode].parent=i;
}
}
void CreatHCode(HTNode ht[],HCode hcd[],int n){ //创建哈夫曼编码
int f,c; //记录c的双亲
HCode hc; //用于遍历所有结点时赋值
for(int i=0;i<n;i++){ //从i到n-1记录的时叶子结点
hc.start=n; //从叶子结点开始遍历,所以先把指针指向最后一个进行储存
c=i; //标记该结点
f=ht[i].parent; //找到双亲
while(f!=-1){ //不是根节点
if(ht[f].lchild==c) hc.cd[--hc.start]='0'; //如果c在双亲左边
else hc.cd[--hc.start]='1'; //右边
c=f; //类似于回溯,将c的双亲变为当前结点,找其双亲
f=ht[f].parent; //找双亲
}
hcd[i]=hc; //记录每个字符的哈夫曼编码
}
}
int main(){
int n;
cout<<"请输入字符数:";
cin>>n;
HTNode ht[2*K];
HCode hcd[K];
for(int i=0;i<n;i++){
cout<<"请输入字符"<<i+1<<":";
cin>>ht[i].data;
cout<<"请输入对应权值:";
cin>>ht[i].weight;
}
CreathufTree(ht,n);
CreatHCode(ht,hcd,n);
cout<<1;
cout<<"哈夫曼树:"<<endl;
for(int i=0;i<2*n-1;i++){
cout << "Node " << i << ": ";
cout << "Data: " << ht[i].data << ", ";
cout << "Weight: " << ht[i].weight << ", ";
cout << "Parent: " << ht[i].parent << ", ";
cout << "Left Child: " << ht[i].lchild << ", ";
cout << "Right Child: " << ht[i].rchild << endl;
}
cout<<"哈夫曼编码:"<<endl;
for(int i=0;i<n;i++){
cout<<ht[i].data<<":";
for(int j=hcd[i].start;j<n;j++)
cout<<hcd[i].cd[j];
cout<<endl;
}
}
提升c++(采用优先队列):
没时间写解释了,自行理解吧,加油。
#include <iostream>
#include <queue>
using namespace std;
struct HTNode {
char data;
int weight;
struct HTNode *parent, *lchild, *rchild;
};
struct compare {
bool operator()(HTNode* a, HTNode* b) {
return a->weight > b->weight;
}
};
HTNode* CreateHuffmanTree(priority_queue<HTNode*, vector<HTNode*>, compare>& dp) {
while (dp.size() > 1) {
HTNode* p = dp.top();
dp.pop();
HTNode* q = dp.top();
dp.pop();
HTNode* s = new HTNode;
s->weight = p->weight + q->weight;
s->lchild = p;
s->rchild = q;
p->parent = q->parent = s;
dp.push(s);
}
return dp.top();
}
void GenerateHuffmanCode(HTNode* root, string code) {
if (!root) return;
if (!root->lchild && !root->rchild) {
cout << root->data << ":" << code << endl;
return;
}
GenerateHuffmanCode(root->lchild, code + "0");
GenerateHuffmanCode(root->rchild, code + "1");
}
int main() {
int n;
cout << "请输入字符数:";
cin >> n;
priority_queue<HTNode*, vector<HTNode*>, compare> dp;
for (int i = 0; i < n; i++) {
HTNode* p = new HTNode;
cout << "请输入字符:";
cin >> p->data;
cout << "请输入权值:";
cin >> p->weight;
p->parent = p->lchild = p->rchild = NULL;
dp.push(p);
}
HTNode* root = CreateHuffmanTree(dp);
cout << "哈夫曼编码结果:" << endl;
GenerateHuffmanCode(root, "");
return 0;
}