哈夫曼编码

 赫夫曼编码
    1.给定一个字符串统计其中的字符的出现的次数,返回一个list<node>集合 node类有askll码和他的权值(出现次数)
    2.然后根据这个list<node>集合,构造一个哈夫曼树.
    3.得到赫夫曼编码
package day20;

import java.nio.charset.StandardCharsets;
import java.util.*;

public class huffManCode {
//    赫夫曼编码
//    给定一个字符串统计其中的字符的出现的次数,返回一个list<node>集合 node类有askll码和他的权值(出现次数)
//    然后根据这个list<node>集合,构造一个哈夫曼树.
//    得到赫夫曼编码

public static void main(String[] args) {
String str =" i like like java do you like java";
    byte[] strBytes = str.getBytes();   //这个集合包含了字符串的所有字符的askll码
//    System.out.println(str.length()); //34
    System.out.println(Arrays.toString(strBytes));
    List<Node> nodes = getNode(strBytes);
    System.out.println(nodes);
//    测试
    System.out.println("赫夫曼树");
    Node huffmantreeroot = createhuffmantree(nodes);
    System.out.println("前序遍历");
    huffmantreeroot.preorder();
//测试是否生成哈夫曼编码
    Map<Byte, String> codes = getCodes(huffmantreeroot);
    System.out.println("生成的哈夫曼编码表为"+codes);
}

//生成赫夫曼树对应的赫夫曼编码
//    思路:
//    1、将赫夫曼编码表存放在map中,Map<Byte,String>
//    32-01    97-100   100-11000
    static Map<Byte,String> huffmancode =new HashMap<Byte,String>();
//2.遍历赫夫曼编码表需要拼接路径,定义一个stringbuilder存储某个叶子节点的路径。
    static StringBuilder stringBuilder =new StringBuilder();
//    stringBulider为一个可变字符串容器。

//  为了调用方便
    private static Map<Byte,String> getCodes(Node root){
        if (root==null ){
            return null;
        }
//     处理root的右子树
        getCodes(root.left,"0",stringBuilder);
        getCodes(root.right,"1",stringBuilder);
        return huffmancode;
    }


    /**
     * 将传入的node节点的所有叶子节点的赫夫曼编码得到,存放到haffmancode集合
     * @param node 传入节点
     * @param code  路径 左子节点为0,右子节点为1.
     * @param stringBuilder   是用于拼接路径
     */
    private static void getCodes(Node node,String code,StringBuilder stringBuilder){
        StringBuilder stringBuilder2 = new StringBuilder(stringBuilder);
//        将code加入stirngbulider2
        stringBuilder2.append(code);
        if (node!=null){
//         判断当前node是否叶子节点
            if (node.data==null){
//                非叶子节点
//                递归左
                getCodes(node.left,"0",stringBuilder2);
//                向右递归
                getCodes(node.right,"1",stringBuilder2);

            }else {
//                node不为空 ,说明为叶子节点
//                就表示找到了叶子节点的最后
                huffmancode.put(node.data,stringBuilder2.toString());

            }
        }
    }





//前序遍历
    public static void preorder(Node root){
    if (root!=null){
        root.preorder();
    }else {
        System.out.println("为空");
    }

    }
//此方法获得了string的字符和所对应的次数。
private static List<Node> getNode(byte[] bytes){ // bytes传入的为所有字符的askll码集合

//    创建arrlist
    ArrayList<Node> nodes = new ArrayList<>();
//  遍历bytes, 统计每个byte出现的次数  map[key是他的askll码的值 ,value是他出现的次数];
    Map<Byte, Integer> counts = new HashMap<>();
    for (byte b:bytes){  //遍历bytes ,以b为单位
        Integer count =counts.get(b);//
//        map的get方法:通过key获得value.

        if (count ==null){ //说明b第一次找到
        counts.put(b,1); //将他设为1
    }else {
            counts.put(b,count+1); //给他加1
        }
    }
//    for结束map就已经完成了统计
//    把每一个键值对转为node
    for (Map.Entry<Byte,Integer> entry :counts.entrySet()){
        nodes.add(new Node(entry.getKey(),entry.getValue()));

        }
    return nodes;
    }

//通过list创建赫夫曼树
private static Node createhuffmantree(List<Node> nodes){
    while (nodes.size()>1){
//        从小到大排序
        Collections.sort(nodes);
//        取出第一颗最小的二叉树
        Node leftnode = nodes.get(0);
        Node rightnode = nodes.get(1);
//        创建新的二叉树,根节点没有data,只有权值。
        Node parentnode =new Node(null, leftnode.weight+ rightnode.weight);
        parentnode.left=leftnode;
        parentnode.right=rightnode;

//      将处理过的两颗二叉树移除
        nodes.remove(leftnode);
        nodes.remove(rightnode);
//        加入新的二叉树
        nodes.add(parentnode);

    }
//    最后返回的为跟节点
    return nodes.get(0);
}
}

class  Node implements Comparable<Node>{
    Byte data;//存放字符本身  ‘a’=97;
    int weight; //权值,表示字符出现的次数
    Node left;
    Node right;

    public Node(Byte data, int weight) {
        this.data = data;
        this.weight = weight;
    }

    @Override
    public int compareTo(Node o) {
//        从小到大排序
        return this.weight-o.weight;
    }
    @Override
    public String toString() { //???????????????///
        return "Node{" +
                "data=" + data +
                ", weight=" + weight +
                '}';
    }

//    前序遍历
    public void preorder(){
        System.out.println(this);
        if (this.left!=null){
            this.left.preorder();
        }
        if (this.right!=null){
            this.right.preorder();
        }

    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值