霍夫曼编码与译码

树和二叉树的应用

一.实验题目:树和二叉树的应用

二.实验内容:哈夫曼编码设计

三.实验目的:掌握树和二叉树的概念及工作原理,运用其原理及概念完成上述实验题中的内容。

四、概要设计原理:

1.选择parent为-1且weight最小的两个结点。其序号分别为s1和s2

2.建立赫夫曼树叶

3.从叶子到根逆向求每个字符的赫夫曼编码

4.输出构造的树

5.输出得到的各权Huffman编码

#include<iostream>
#include<iomanip>
using namespace std;
struct HaffNode
{
    int weight;
    int parent;
    int lchild;
    int rchild;
};
struct HaffCode
{
    int bit[10000];   //编码位
    int start;        //编码开始的位置
    int weight;
    char c;             //编码所对应的字符
};
/*
      由于n个叶子结点,要合并n-1次。每次从
   还无双亲(无双亲代表还未合并过)
   的叶子结点中选择权值最小的两个叶子结点进行合并,
   新结点下标为这两个叶子的双亲,新结点的权值为这两个叶子权值之和,
   左孩子为最小结点下标,右孩子为次小结点下标,叶子值不需要,双亲为0。
*/
void CreateHaffman(int w[],int n,HaffNode ht[])
{
    //建立叶结点个数为n,权值为weight的哈夫曼树haffTree
    int i,j,m1,m2,x1,x2;
    //哈夫曼树haffTree初始化。n个叶结点的哈夫曼树共有2n-1个结点
    for(i=0;i<2*n-1;i++)
    {
        if(i<n)
            ht[i].weight=w[i];
        else
            ht[i].weight=0;
            ht[i].parent=0;
            ht[i].lchild=-1;
            ht[i].rchild=-1;
    }
    //构造哈夫曼树haffTree的n-1个非叶结点
   for(i=0;i<n-1;i++)
   {
      m1=m2=1000;
      x1=x2=0;
      for(j=0;j<n+i;j++)//循环找出所有权重中,最小的二个值
      {
          if(ht[j].weight<m1&&ht[j].parent==0)
          {
              m1=ht[j].weight;
              x1=j;
          }
          else if(ht[j].weight<m2&&ht[j].parent==0)
          {
              m2=ht[j].weight;
              x2=j;
          }
      }
      //将找出的两棵权值最小的子树合并为一棵子树
      ht[x1].parent=n+i;//新结点下标为这两个叶子的双亲,
      ht[x2].parent=n+i;
      ht[n+i].weight=ht[x1].weight+ht[x2].weight;//新结点的权值为这两个叶子权值之和
      ht[n+i].lchild=x1;
      ht[n+i].rchild=x2;
 }
}
void encoded(int n,char ch[],HaffNode ht[],HaffCode hc[])
{
    //由n个结点的哈夫曼树haffTree构造哈夫曼编码haffCode
    HaffCode cd;
    int child,parent,i,j;
    //求n个叶结点的哈夫曼编码
    for(i=0;i<n;i++)
    {
        cd.start=n-1;
        cd.c=ch[i];
        cd.weight=ht[i].weight;//取得编码对应权值的字符
        child=i;
        parent=ht[child].parent;//由叶结点向上直到根结点
        while(parent!=0)
        {
            if(ht[parent].lchild==child)
                cd.bit[cd.start]=0;//左孩子结点编码0
            else
                cd.bit[cd.start]=1;//右孩子结点编码1
                cd.start--;
                child=parent;
                parent=ht[child].parent;
        }
    //保存叶结点的编码和不等长编码的起始位
        for(j=cd.start+1;j<n;j++)//重新修改编码,从根节点开始计数
            hc[i].bit[j]=cd.bit[j];
        hc[i].start=cd.start;
        hc[i].weight=cd.weight;//保存编码对应的权值
        hc[i].c=cd.c;
        cout<<"字符"<<cd.c<<"的权值为:"<<hc[i].weight<<"   code=";
        for(j=hc[i].start+1;j<n;j++)
            cout<<hc[i].bit[j];
        cout<<endl;

    }

}
void transcode(int n,HaffNode ht[],HaffCode hc[])
{
    int a=2*n-2;
    char b;
    cout<<"请输入一串二进制编码(0,1以外的数结束)"<<endl;
    cin>>b;
    while((b=='0')||(b=='1'))
    {
        if(b=='0')
            a=ht[a].lchild;
        else
            a=ht[a].rchild;
        if(ht[a].lchild==-1)
        {
            cout<<hc[a].c;
            a=2*n-2;
        }

         cin>>b;
    }
}
int main()
{
    int w[1000];//权值数组
    char ch[1000];//代码数组
    int n,a;
    cout<<"共有叶子数:"<<endl;
    cin>>n;
    cout<<"依次输入每个叶子的权值:"<<endl;
    for(a=0;a<n;a++)
        cin>>w[a];
    cout<<"依次输入每个叶子所代表代码:"<<endl;
    for(a=0;a<n;a++)
        cin>>ch[a];

    HaffNode* ht=new HaffNode[2*n-1];//树结点数组
    HaffCode* hc=new HaffCode[n];//编码数组
    CreateHaffman(w,n,ht);
    encoded(n,ch,ht,hc);
    transcode(n,ht,hc);
    return 0;
}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值