哈夫曼编码
哈夫曼编码
- 字符都有ASC2码,长度一样,占用空间一样。根据字符使用频率编码可以省空间,就是哈夫曼编码。
- 统计每个字符出现的频率,插入队列中。
- 降序排序该队列。
- 取出最小的两个节点合并成父节点插入队列里。该两节点和父节点形成一个二叉树。
- 重复3、4过程,使队列仅剩一个节点。该节点是最后的根,前面生成的二叉树都是该二叉树的节点。
- 叶子节点就是字符。
- 左树0,右树1,从根到叶子节点就会生成由0、1组成的码,就是哈夫曼编码,
队列生成二叉树过程
生成的哈夫曼编码
代码
#include <bits/stdc++.h>
using namespace std;
string s=“All roads lead to Rome.”;
int sl;//输入字符串长度
//根据每个字符出现的频率,生成对应的哈夫曼编码
struct node{
char c;//字符
int cx,d;//字符ASC2值和出现的频率
string s,s1;//哈夫曼编码和合并后的字母
node *fa,*left,*right;//父和左右子树
node(){//无参数初始化
d=0,s=s1=“”;
left=right=fa=NULL;
}
node(char x){
d=0,c=x,cx=int(x),s=“”,s1=x;
left=right=fa=NULL;
}
node(node *a1,node *a2){//合并两节点。变成该节点的左右子树
d=a1->d+a2->d;s1=a1->s1+a2->s1;
a1->fa=a2->fa=this;
left=a1,right=a2;
}
}a[256],//共256个字符,每个都是节点(取地址)。
*n1,*n2// 左右节点都用指针
,head;//哈夫曼树的根
vector<node> v;//指针容器
void mk(node *x,string s){//生成编码过程,
if(x->left)mk(x->left,s+‘0’);//左0到
if(x->right)mk(x->right,s+‘1’);//右1,
x->s=s;//非左右树就是叶节点,就是字符,需要编码
}
bool cmp(const node *a,const node *b){//指针数组排序函数
return a->d>b->d;
}
bool cmp2(node a,node b){//所有字符的结构体数组排序函数
return a.s.length()<b.s.length();
}
int main(){
//freopen(“data.cpp”,“r”,stdin);
//getline(cin,s);
sl=s.length();
for(int i=0;i<265;i++)a[i]=node{char(i)};//每个字符结构体初始化
for(int i=0;i<sl;i++)a[int(s[i])].d++;//每个字符出现频率计算
for(int i=0;i<265;i++)//只要出现的字符就放进队列里
if(a[i].d)v.push_back(&a[i]);
while(!v.empty()){//一直到清空队列,
if(v.size()==1){//剩下一个元素作为根
head=v.back();v.pop_back();break;
}else{//排序,取出最小两个节点合并成一个节点,作为树放进队列
sort(v.begin(),v.end(),cmp);
n1=v.back();v.pop_back(); n2=v.back();v.pop_back();
for(int i=0;i<v.size();i++)cout<<v[i]->s1<<“,”<<v[i]->d<<“|”;
cout<<endl;
node *f=new node(n1,n2);
v.push_back(f);
}
}
cout<<s<<endl;
mk(head,“”);//递归,生成编码
sort(a+0,a+256,cmp2);//排序
for(int i=0;i<256;i++){
if(a[i].d)cout<<a[i].c<<“\t”<<a[i].d<<“\t”<<a[i].s<<endl;
}
return 0;
}
小结
别慌,别急, 有些概念光听一听,挺吓人的,真的做好慢慢去做还真能做出来。
原文地址:https://blog.csdn.net/adam_life/article/details/140576906
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!