赫夫曼编码
来源:互联网 发布:阿里云测试培训 编辑:程序博客网 时间:2024/06/05 03:34
//赫夫曼编码:最优二叉树,是带权路径长度最短的二叉树; 根据结点的个数和权值不同,最优二叉树的形状也不同
//将每个带有权值的结点作为一颗仅有根结点 的二叉树,树的权值为节点的权值
//将其中两颗权值最小 的树组成一颗新二叉树,新树的权值为两棵树的权值和
//重复上述两个步骤
//最优二叉树的左右子树可以互换,不影响树的带权路径长度
//最优二叉树的节点数是叶子的2倍-1;
//赫夫曼编码:设置初态——获取终态——从叶子到根逆序编码
首先创建赫夫曼树,N个叶子有2*n-1个结点的树,用顺序存储结构a[]存储;初态设置如上图(a)所示;parent=-1表示该结点还未被访问
接下来,从数组中选取两个weight最小的叶子结点构造新的结点,如a[6]:weight=3和a[0]:weight=5构成结点a[8]:weight=8;结点a[8]的左右孩子分别填充序号6、0;依次填充直至完成;
最后进行编码,若为左子树取0,右子树取1; 从叶子结点向根节点进行逆序编码;请仔细查看上图,发现最后一行,即根节点的parnet=-1,以次判断是否从叶子编码至根节点;
(详见严蔚敏de《数据结构》和高一凡的《数据结构算法和分析(STL版)》)
#include<vector>template<class T> struct HTNode{ T weight; int parent,lchild,rchild;}; template<class T>class HuffmanTree{ private: vector<HTNode>> HT; //树的顺序存储结构 int N; bool Make; void Select(int i,T&j1,T&j2) const{ //返回前i个节点中权值最小和次小的两个树的结点序号 int i,m; for(j=0;j<i,HT[j].parent!=-1;j++); j1=j; for(j=j1+1;j<i,HT[j].parent!=-1;j++); if(HT[j].weight<HT[j1].weight){ j2=j1; j1=j; }else j2=j; // 确保j1<j2 //parent=-1;表示此叶子还未被访问 for(m=j+1;m<i;m++){ if(HT[m].parent==-1 && HT[m].weight<HT[j1].weight){ j2=j1; j1=m; }else if(HT[m].parent==-1&& HT[m].weight<HT[j2].weight) j2=m; } } public: HuffmanTree(){ Make=false; } void CreateHT(string FileName){ ifstream fin(FileName.c_str()); fin>>N; //叶子个数 if(N<=1) return; int i,s1,s2; HT.assign(2*N-1); //赫夫曼树的结点总数; //初态:输入前N个叶子的权值,其余Parent、lchild、rchild全为-1; for(i=0;i<N;i++){ fin>>HT[i].weight; cout<<HT[i].weight<<" "; HT[i].parent=-1; HT[i].lchild=-1; HT[i].rchild=-1;} cout<<endl; fin>>close(); //终态: for(i=N;i<HT.size();i++){ Select(i,s1,s2); HT[s1].parent=HT[s2].parent=i; HT[i].weight=HT[s1].weight+HT[s2].weight; HT[i].lchild=s1; HT[i].rchild=s2; } Make=true; //建立赫夫曼树的标志 } //编码 void HuffmanCodingLeaf() const{ if(Make){ string *HC=new string[N]; assert(HC!=NULL); cout<<"从叶子到根逆向求得赫夫曼编码:"<<endl; for(int i=0;i<N;i++){ for(int c=i,p=HT[i].parent; p>=0; c=p;p=HT[p].parent){ if(c==HT[p].lchild) HT[i].insert(0,"0"); else HC[i].insert(0,"1"); cout<<HC[i]<<endl; } } delete []HC; } } void HuffmanTree(){ if(Make){ string str="",*HC=new string[N]; assert(HC!=NULL); vector<int> s(HT.size(),0);//访问标志012 int c=HT.size()-1;//根节点的序号 while(c>-1){ if(s[c]==0){//未被访问 s[c]=1; if(HT[c].lchild>-1){ c=HT[c].lchild; str+='0'; } else{ HC[c]=str; c=HT[c].parent;//向根方向后退一步 str.erase(str.size()-1,1); } } else if(s[c]==1){ s[c]=2; c=HT[c].rchild; str+='1'; } else{ c=HT[c].parent; if(c>-1) str.erase(str.size()-1,1); } } cout<<"无栈非递归从根到叶子求得的赫夫曼编码:"<<endl; for(int i=0;i<N;i++) cout<<HC[i]<<endl; delete []HC; } } };
阅读全文
0 0
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码!
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码
- 单片机与数字电路抗干扰措施
- java1.8 lambda表达式 函数式编程 闭包
- Canvas基础知识
- C++中的Compare()函数用法
- Android工程方法数超过65535,怎么破
- 赫夫曼编码
- 重新搭建eclipse、android、tomcat平台
- Android 仿火萤视频桌面 神奇的LiveWallPaper
- hadoop部署参考
- Git命令
- 单点登录原理与简单实现
- iOS IPV6审核被拒
- 0013、node 之网址处理
- macbook pro外界键盘更换command与ctrl键功能