小白级讲解【有图】+完整源码--哈夫曼树构造和哈夫曼编码

哈夫曼树

给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

给定如下数据:
在这里插入图片描述
要求构造哈夫曼树、输出哈夫曼编码以及计算平均查找长度。

根据哈夫曼树的定义,我们可以如下进行构造:
定义一个map 将单词与频度对应起来,再根据频度进行构造树。

构造步骤如下:

先从上面选出两个最小的(上面的频度恰好是按降序排列的):
在这里插入图片描述
此时123和124合成了一个新的节点245,
用形成的节点和剩下没被选中的节点重复上面步骤,具体如下:
在这里插入图片描述
继续选最小两个····

在这里插入图片描述
继续选最小两个····
在这里插入图片描述
····
在这里插入图片描述
以此类推…
最后成树如下:
在这里插入图片描述
具体过程如上。权值是口算的,如果权值算错请多谅解,看懂步骤就好。
哈夫曼树可以不唯一,因为左右子树可以互换。

以下为代码部分,在这里我是用数组来存贮树节点的,数组大小为2n。
假设刚开始有n个节点,则最终形成的哈夫曼树有2
n-1个节点。
因为此时的n个初始节点可全部看成树的n个叶子节点(实际也是如此),树的非叶子节点为n-1个,则总结点数m=2n-1,所以声明2n个节点空间刚好够用。坐标为0的空间不做处理(坐标1~n存贮n个初始节点),从坐标n+1开始形成哈夫曼树,最终坐标为2n-1时为树的根节点

具体的请看里面的注释,因为和代码一起看才更容易懂。
以下为代码部分:

代码

#include<string>
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
const int nums= 15;
typedef struct{
    int weight;
    int parent,lchild,rchild;
}HTNode,*HuffmanTree;

void Select(HuffmanTree HT,int n,int &s1,int &s2){
//s1,s2分别是权值最小和次小的。
    int minum;
    for(int i=1;i<=n;i++){//初始化minum。parent为0(即表示 还没有被选择的节点)
        if(HT[i].parent==0){
            minum=i; break;
        }
    }
    for(int i=1;i<=n;i++){
        if(HT[i].parent==0){
            if(HT[i].weight<HT[minum].weight)
                minum=i;
        }
    }
    s1=minum;//最小值
    for(int i=1;i<=n;i++){
        if(HT[i].parent==0 && i!=s1){
            minum=i; break;
        }
    }
    for(int i=1;i<=n;i++){
        if(HT[i].parent == 0 && i != s1)
            if(HT[i].weight < HT[minum].weight)
                minum = i;
    }
    s2=minum;//次小值
    return ;
}

void CreateHuffmanTree(HuffmanTree &HT,int n,int ar[]){
    if(n<=1) return ;
    int m=2*n-1;
    int s1,s2,i;
    
    //初始化
    for(i=1;i<=m;i++){
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
    }
    for(i=1;i<=n;i++){
        HT[i].weight=ar[i-1];
    }
//构造哈夫曼树
    for(int i=n+1;i<=m;i++){
    //从第n+1个位置开始,,在前n个节点中选择最小的两个节点 在n+1的位置形成新节点。
    //进入下一个循环(即i++),则把新形成的节点包括进去比较选择最小两个。
        Select(HT,i-1,s1,s2);
        HT[s1].parent=i;HT[s2].parent=i;

        HT[i].lchild=s1;HT[i].rchild=s2;
        HT[i].weight=HT[s1].weight+HT[s2].weight;
    }
}

void SetHuffCode(HuffmanTree HT,int n,string code,map<int,string>&p){
    for(int i=1;i<=n;i++){
        int current=i;
        int father=HT[i].parent;
        int rem;
        while(father){
            if(HT[father].lchild==current)
                code='0'+code;
            else code='1'+code;
            current=father;
            father=HT[father].parent;
        }
        p[HT[i].weight]=code;
        code.clear();
    }
}


int main()
{
    int ar[nums]={1192,677,541,518,462,450,242,195,190,181,174,157,138,124,123};
    string ar_S[nums]={"The","of","a","to","and","in","that","he","is","at","on","for","His","are","be"};
    map<int,string>p_str;
    map<int,string>p_code;
    for(int i=0;i<nums;i++) p_str[ar[i]]=ar_S[i];

    HuffmanTree HT=(HuffmanTree)malloc((2*nums)*sizeof(HTNode));
    CreateHuffmanTree(HT,nums,ar);
    
    SetHuffCode(HT,nums,"",p_code);

    cout<<"The HuCode of strs:"<<endl;
    int j=0,m=0;
    double lenght=0;
    for(int i=0;i<nums;i++){
        cout<<p_str[ar[i]]<<'\t'<<ar[i]<<'\t'<<p_code[ar[i]]<<endl;
        j=p_code[ar[i]].size();
        m+=ar[i];
        lenght+=ar[i]*j;
    }
    cout<<"Aver:"<<1.0*lenght/m<<endl;
    system("pause");
    return 0;
}

完结撒花。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值