哈夫曼树

哈夫曼树(最优二叉树)

视频教程
哈夫曼编码是现代压缩算法的基础,是一种前缀码,即任意一个字符的二进制编码都不是其他字符的前缀

一.算法步骤与特点总结

①以权值作为根节点构建n棵二叉树,组成森林
②在森林中选出根据节点最小的两棵树合并作为一个新树的左右子树,新树的根节点为其左右子树的根节点之和
③从森林中删除刚才选取的两棵树并将新树加入森林
④重复上述步骤直到只剩下一棵树,该树便是哈夫曼树(最优二叉树)
在这里插入图片描述
带权路径长度即WPL

二.代码实现

第一步:定义节点

//定义节点
class Node
{
    int weight;//节点的权重
    int r_link;//右子节点
    int l_link;//左子节点
    int p_link;//父节点
    char c;
    public Node()
    {
        this.l_link=0;
        this.p_link=0;
        this.r_link=0;
    }
    //初始化
    public Node(int weight,char c)
    {
        this.l_link=0;
        this.p_link=0;
        this.r_link=0;
        this.weight=weight;
        this.c = c;
    }
}

第二步:构建哈夫曼树并实现功能

//构建哈夫曼树
class Solution {
    //采用静态三叉链表
    Node node[];
    char strs[];
    int rates[];
    int min_index,second_min;
    Map<Character,String> map ;//用来存储字符对应的二进制串
    //strs包含了所有出现字符,rates表示每一个字符出现的频率
    public Solution(char[] strs,int rates[])
    {
        this.rates = rates;
        this.strs = strs;
        //这里我们使用索引为1-2*strs.length-1的节点
        this.node=new Node[2*strs.length];
        for(int i=1;i<2*strs.length;i++)
        {
            if(i<=strs.length)//前n个字符将字符与权重存进去
                this.node[i] = new Node(rates[i-1],strs[i-1]);
            else//后n个字符用下面的
                this.node[i]=new Node();
        }
    }
	
	//构建haffunman树
    private  void BuildHaffuman()
    {
        for(int i = strs.length+1;i<=2*strs.length-1;i++)
        {
            //选择最小的与次小的
            select(i-1);
            node[min_index].p_link=i;
            node[second_min].p_link=i;
            node[i].r_link=min_index;
            node[i].l_link=second_min;
            node[i].weight=node[min_index].weight+node[second_min].weight;
        }
    }

    //传入参数表示从1到N节点的权值最小的两个树
     void select(int N)
    {
        int min_weight,second_min_weight;
        int index=1;
        //寻找索引最小的两个树
        while(node[index].p_link!=0)
            index++;
        min_index=index;
        min_weight=node[min_index].weight;
        index++;
        while(node[index].p_link!=0)
            index++;
        second_min=index;
        second_min_weight=node[second_min].weight;
        //将找到的最小的结果比较,如果犯了则交换
        if(second_min_weight<min_weight)
        {
            int temp=second_min_weight;
            second_min_weight=min_weight;
            min_weight=temp;
            temp=min_index;
            min_index=second_min;
            second_min=temp;
        }
        //继续往后找
        for(int i=index+1;i<=N;i++)
        {
            if(node[i].p_link==0)
            {
                if(node[i].weight<=min_weight)//注意等号
                {
                    second_min_weight = min_weight;
                    second_min=min_index;
                    min_weight=node[i].weight;
                    min_index=i;
                }
                else if(node[i].weight>min_weight&&node[i].weight<second_min_weight)
                {
                    second_min_weight=node[i].weight;
                    second_min = i;
                }
            }
        }
    }
	//编码并返回一个map保存
    public Map<Character,String> encodeStr()
    {
        Map<Character,String> map = new HashMap<>();
        BuildHaffuman();
        for(int i=0;i<strs.length;i++)
        {
            map.put(strs[i],getStringOfChar(i+1));
        }
        this.map=map;//这里我做了两道,既全局map保存,也返回
        return  map;
    }
	
	//从对应的索引开始往上走直到树顶,对于左节点编码0,右节点编码1
	//实际上index的范围为1-N,因为前N个节点对应了字符
    private String getStringOfChar(int index)
    {
        String s ="";
        int p_link=node[index].p_link;
        while(p_link!=0)
        {
            if(node[p_link].l_link==index)
                s+="0";
            else
                s+="1";
            index = p_link;
            p_link = node[p_link].p_link;
        }
        return  new StringBuffer(s).reverse().toString();//这里需要反转一下
    }
	
	//解码
    public  String decodeStr(String s)
    {
        String  str="";
        for(char c : s.toCharArray())
        {
            str+=map.get(c);
        }
        return str;
    }
}

第三步:测试

import org.junit.Test;
import java.util.HashMap;
import java.util.Map;

public class Math {
    @Test
    public void Test() {
        char strs[]=new char[]{'a','b','c','d'};
        int rates[]=new int[]{1,3,5,2};
        Solution s =  new Solution(strs,rates);
        Map<Character, String> characterStringMap = s.encodeStr();
        System.out.println(characterStringMap);
        System.out.println(s.decodeStr("abccd"));
    }
}

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值