目标
已知一组包含至少8个字符的数组及各字符的出现概率。求该字符串数组的哈夫曼编码及平均码长。
1.什么是Huffman编码
例如:c++一个字符是8bit,在传输时就会发送8bit,那么8个字符,就是8*8=64bit。Huffman编码对这些字符进行编码,将8字符变为了26bit,节约了空间
本文主要是代码实现,需要懂原理的建议看其他的博主文章,或则看我代码中的解释
以下是代码:
#include<iostream>
#include<time.h>
#include<stdlib.h>
#include<list>
#include <algorithm>
using namespace std;
#define CHARNUM 8//表示字符数;
#define HUFNODE (2*CHARNUM)//用于表示创建humffmantree的节点的多少
class Node{
public:
double weight=-1;
char c;
int left=-1;
int right=-1;
string code="";
Node(){}
Node(double weight,char c){
(*this).weight=weight;
(*this).c=c;
}
};
bool cmp(Node *a,Node *b){
return a->weight<b->weight;
}
class HumfTree{
public :
//创建一个数组,记录数据
Node *node[HUFNODE];
Node *node1[HUFNODE-1];
HumfTree(){
}
// 初始化humffmantree;
// 对数组进行赋值;
void init(){
// 对每个节点进行赋值;
int arr[CHARNUM];
double sum=0;
double weight;
for(int i=0;i<CHARNUM;i++){
arr[i] = rand()%15+1;
sum+=arr[i];
}
for(int i=0;i<CHARNUM;i++){
weight=arr[i]/sum;
node[i] = new Node(weight,char(97+i));
}
}
// 创建一个树,
void createTree(){
int nodeNum=CHARNUM;
int index=CHARNUM;
int pre;
Node temp;
for(int i=0;i<CHARNUM-1;i++){
// cout<<i<<endl;
//cout<<i-(CHARNUM-1)<<endl;
pre=2*i;
// cout<<i+CHARNUM<<endl;
sort(node+pre,node+pre+CHARNUM-i,cmp);
node[i+CHARNUM] = new Node((node[pre]->weight+node[pre+1]->weight),'.');
node[i+CHARNUM]->left=pre;
node[i+CHARNUM]->right=pre+1;
}
}
// 以下两个方法表示进行前序遍历这个树 ,
void preOrder(){
selectAndCode(HUFNODE-2,"");
}
//遍历方法1.0
//这里遍历逻辑树,没有编码
void select(int index){
cout<<node[index]->c<<":"<<node[index]->weight<<endl;
if(node[index]->left!=-1){
select(node[index]->left);
}
if(node[index]->right!=-1){
select(node[index]->right);
}
}
//遍历方法2.0
//这个方法用于前序遍历和编码
void selectAndCode(int index,string s){
cout<<node[index]->c<<":"<<node[index]->weight<<endl;
if(node[index]->c!='.'){
node[index]->code=s;
}
if(node[index]->left!=-1){
selectAndCode(node[index]->left,s+"0");
}
if(node[index]->right!=-1){
selectAndCode(node[index]->right,s+"1");
}
}
//该方法用于展示字符的huffman编码
void showCharCode(){
for(int i=0;i<HUFNODE-1;i++){
if(node[i]->c!='.'){
cout<<node[i]->c<<":"<<node[i]->code<<endl;
}
}
}
//用于测试的方法;
void show(){
double j=0;
for(int i=0;i<8;i++){
cout<<node[i]->c<<"权重"<<node[i]->weight<<endl;
j+=node[i]->weight;
}
cout<<"和"<<j<<endl<<endl;
}
//计算wpi
double getWPI(){
double ans=0;
for(int i=0;i<HUFNODE-1;i++){
if(node[i]->c!='.'){
cout<<node[i]->c<<":"<<node[i]->code<<endl;
//计算wpi
double w=node[i]->weight;
int len=node[i]->code.length();
ans+=w*len;
}
}
return ans;
}
};
int main(){
//改行代码用于生成随机数,不改变改行代码,生成的随机数不会改变,方便用于测试代码
// srand((int)time(0));
HumfTree tree;
tree.init();
//显示一下各个数的权重
tree.show();
tree.createTree();
//前序遍历
cout<<"前序遍历"<<endl;
tree.preOrder();
//显示编码;
cout<<endl<<"显示编码"<<endl;
tree.showCharCode();
cout<<"....."<<endl;
//显示wpi
double wpi=tree.getWPI();
cout<<endl<<"wpi="<<wpi<<endl;
return 0;
}
下面是原理分析,
下面是
结果验证
有问题可以加我qq
2086385336