霍夫曼树

定义:

  1. 路径: 树中一个结点到另一个结点之间的分支构成这两个结点之间的路径。
  2. 路径长度:路径上的分枝数目称作路径长度。
  3. 树的路径长度:从树根到每一个结点的路径长度之和。
  4. 结点的带权路径长度:在一棵树中,如果其结点上附带有一个权值,通常把该结点的路径长度与该结点上的权值之积称为该结点的带权路径长度(weighted path length)

构造方法:

这里写图片描述

霍夫曼树编码解码:

#include<iostream>
#include<string>
using namespace std;
typedef struct HTNode//定义节点
{
    char c;//节点的内容
    double weight;//权值
    int parent;//父节点
    int lchild;//左子节点
    int rchild;//右子节点
};

void creatHFMTree(HTNode* ht,int n)//n是叶子节点总数
{
    int lchild,rchild;//权值最小的两个子节点
    double wl,wr;//最小的两个权值
    for(int i=0;i<2*n-1;i++)
        ht[i].parent=ht[i].lchild=ht[i].rchild=-1;

    for(int i=n;i<2*n-1;i++)//求解非叶子节点
    {
        wl=wr=DBL_MAX;
        lchild=rchild=-1;
        for(int j=0;j<i;j++)
        {
            if(ht[j].parent==-1)//ht[j]是否在森林中
            {
                if(ht[j].weight<wl)//定义wl<=wr
                {
                    wr=wl;
                    wl=ht[j].weight;
                    rchild=lchild;
                    lchild=j;
                }
                else if(ht[j].weight<wr)
                {
                    wr=ht[j].weight;
                    rchild=j;
                }
            }
        }
        ht[lchild].parent=ht[rchild].parent=i;//获得森林中权值最小两个节点的父节点
        ht[i].weight=wl+wr;//更新父节点的信息
        ht[i].lchild=lchild;
        ht[i].rchild=rchild;
    }
}

typedef struct HTCode//code定义为路径,由于编码长度不定,所以需要指定路径的起始位置
{
    char* code;
    int start;
};

void creatHFMCode(HTNode* hn,HTCode* hc,int n)
{
    int f,tmp;
    for(int i=0;i<n;i++)
    {
        hc[i].start=n;//由于存在n个节点,编码长度不可能多余n
        tmp=i;
        while((f=hn[tmp].parent)!=-1)//从底往上遍历,直至到根节点
        {
            if(hn[f].lchild==tmp)
                hc[i].code[hc[i].start--]='0';
            else
                hc[i].code[hc[i].start--]='1';
            tmp=f;
        }
        hc[i].start++;//由于最后一次,进行了start--操作,故需要复原       
    }
}
void printCode(HTCode* hc,HTNode* hn ,int n)
{
    for(int i=0;i<n;i++)
    {
        cout<<hn[i].c<<":";
        for(int j=hc[i].start;j<=n;j++)
            cout<<hc[i].code[j];
        cout<<endl;
    }
}

void decoding(string s,HTNode* nodes,int num)
{
    int root=num-1;
    int tmpNode=root;
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='0')
            tmpNode=nodes[tmpNode].lchild;
        else if(s[i]=='1')
            tmpNode=nodes[tmpNode].rchild;
        else
        {
            cout<<"error input"<<endl;
            return;
        }
        if(nodes[tmpNode].lchild==-1)//当某个节点为叶子节点时便可以输出,同时重新从根节点开始遍历
        {
            cout<<nodes[tmpNode].c;
            tmpNode=root;
        }

    }
    cout<<endl;
}
int main()
{
    int num=10;
    HTNode* nodes=new HTNode[2*num-1];//霍夫曼树是基于数组实现的
    for(int i=0;i<num;i++)
    {
        nodes[i].c=i+'a';
        nodes[i].weight=i+2;
    }//初始化所有叶子节点
    creatHFMTree(nodes,num);//构造霍夫曼树
    HTCode* codes=new HTCode[num];//定义霍夫曼编码数组
    for(int i=0;i<num;i++)//由于每个编码结构体中存在一个指针成员,故需要初始化这些成员
        codes[i].code=new char;
    creatHFMCode(nodes,codes,num);//获取霍夫曼编码
    printCode(codes,nodes,num);

    string s="000000011010";
    decoding(s,nodes,2*num-1);//霍夫曼解码

    delete[] nodes;
    delete[] codes;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值