HuffmanTree的实现及Huffman编码

HuffTree的定义:

假设一共有n个data,第i个data有对应的权值wi。使从根节点到所有data的路径长度乘以其权值和为最小。符合其条件的树就是HuffmanTree,也被称为最优二叉树。

实现步骤:

  1. 先将n个data建成n个只有一个根节点的数
  2. 然后从n个中找出两个最小的data
  3. 将这两个数合并为一个二叉树,左孩子为最小值,右孩子为第二小值
  4. 将这个树的根节点的权值设为原来两个点的权值之和
  5. 在剩下的n-1个根节点中执行步骤2
  6. 直到只剩下一个根节点,结束循环。

下面来讲一下HuffmanTree的一个最经典的应用,Huffman编码。

(以下定义摘自百度百科)
Huffman编码是一种无前缀变字长编码。解码时不会混淆。
使用Huffman编码的前提是知道每一个字母出现的频率。
在编码时,字母出现的频率相当于HuffmanTree中的data的权值。然后从根节点开始,每经过一个左子树,编码加一个0。每经过一个右子树,编码加一个1。
这样建树之后,每一个字母都有自己的唯一编码,且无重复前缀。

HuffmanTree及编码的实现代码:

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=100;
typedef struct {
    int weight;
    int parent,lchild,rchild;
}HafNode;//HuffmanTree的基本定义
typedef struct {
    int weight;
    char data;
    char code[maxn];//需要被建树的信息
}HafCode;
void Init(HafCode *h,int &n)//初始化输入数据
{
    cout<<"Input The Number"<<endl;
    cin>>n;
    cout<<"Input The Character And Weight"<<endl;
    for(int i=0;i<n;++i)
        cin>>h[i].data>>h[i].weight;
}
void select(HafNode *h,int k,int &s1,int &s2)//选择两个最小的值
{
    int i;
    for(i=0; i<k && h[i].parent != 0; ++i);//选择一个父节点为0的根节点
    s1 = i;
    for(i=0; i<k; ++i){
        if(h[i].parent==0 && h[i].weight<h[s1].weight)
              s1 = i;
    }
    for(i=0; i<k; ++i){
        if(h[i].parent==0 && i!=s1)
            break;
    }
    s2 = i;
    for(i=0; i<k; ++i){
        if(h[i].parent==0 && i!=s1 && h[i].weight<h[s2].weight)
            s2 = i;
    }
}
void Huffman(HafCode *h2,HafNode *h1,int n)
{
    char str[maxn];
    int m=2*n-1;
    for(int i=0;i<m;++i){
        if(i<n)//前n个全部是叶子节点,
            h1[i].weight=h2[i].weight;
        else//后面的是还没建成的树
            h1[i].weight==0;
        h1[i].lchild=h1[i].parent=h1[i].rchild=0;
    }
    int s1,s2;
    for(int i=n;i<m;++i){
        select(h1,i,s1,s2);
        h1[s1].parent=i;//建立二叉树
        h1[s2].parent=i;
        h1[i].lchild=s1;
        h1[i].rchild=s2;
        h1[i].weight=h1[s1].weight+h1[s2].weight;
        //cout<<h1[s1].weight<<" "<<h1[s2].weight<<endl;
    }
    str[n]='\0';
    //memset(str,0,sizeof(str));
    int l,p;
    for(int i=0;i<n;++i){//从每个叶子节点开始倒序遍历
        l=n-1;//倒序赋值字符串
        //cout<<h2[i].data<<endl;
        for(int k=i,p=h1[k].parent;p;k=p,p=h1[k].parent){//沿着叶子回溯到根节点
            if(k==h1[p].lchild)
                str[l]='0';
            else
                str[l]='1';
           // cout<<str[l];
            l--;
        }
        //cout<<endl;
        strcpy(h2[i].code,str+l+1);
    }
}
int main()
{
    int n;
    HafCode hc[maxn];
    HafNode tree[maxn];
    Init(hc,n);
    Huffman(hc,tree,n);
    for(int i=0;i<n;++i)
        cout<<hc[i].data<<" "<<hc[i].code<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值