哈夫曼编码

在电讯通信中的经典应用。
数据无损压缩。
使用哈夫曼编码;任何编码不可能是另一个编码的前缀编码,不会咋成匹配的多译性。空格01.

package com;

import java.util.*;

public class HuffmanCode {
  public static void main(String[] args) {
    //
      String str="I like like like java do you like a java";
      byte[] bytes = str.getBytes();
    System.out.println(bytes.length);
      List<Node> nodes = getNodes(bytes);
    System.out.println(nodes);
    System.out.println("---------------");
      Node root = createHuffmanTree(nodes);


    System.out.println("------------------");
      Map<Byte, String> codes = getCodes(root);
    System.out.println(codes);
  }


  //为了方便调用,重载
    private static Map<Byte,String>getCodes(Node root){
      if(root==null)
          return null;
      else{
          getCodes(root.left,"0",stringBuilder);
          getCodes(root.right,"1",stringBuilder);
      }
      return huffmanCode;
    }

  //创建对应的哈夫曼编码表
    //1.将哈夫曼编码表存放在Map<Byte,Integer> 形式
    static Map<Byte,String> huffmanCode=new HashMap<>();
    //2.在生成哈夫曼编码时,需要去拼接路径,定义一个StringBuilder,存储某个叶子结点的路径
  static StringBuilder stringBuilder=new StringBuilder();

    //功能:将传入的node结点的而所有叶子结点哈夫曼编码存放到huffmanCode集合中
    //code:路径   左0右1
    //StringBuilder:用拼接路径

    private static void getCodes(Node node,String code,StringBuilder stringBuilder){
  StringBuilder stringBuilder2=new StringBuilder(stringBuilder);   //?????为啥不能直接用????
        stringBuilder2.append(code);
        if(node!=null){
            //判断是叶子结点还是非叶子结点
            if(node.data==null){  //非叶子结点
//向左递归
               getCodes(node.left,"0",stringBuilder2);
               getCodes(node.right,"1",stringBuilder2);
            }else{  //说明是叶子结点
                //表示找道某个叶子结点的最后
                huffmanCode.put(node.data,stringBuilder2.toString());

            }

        }
    }

  //bytes:接受字节数组
    //返回List的Node集合
  private static List<Node> getNodes(byte[] bytes){
      //创建一个ArrayList
      ArrayList<Node> nodes=new ArrayList<Node>();

      //遍历byte,统计每个字符出现的次数,map[key,value]
      Map<Byte,Integer> counts=new HashMap<>();
      for(byte b:bytes){
          Integer count=counts.get(b);
          if(count==null){
              counts.put(b,1);
          }else{
              counts.put(b,count+1);  //之后添加的会覆盖之前添加的
          }
      }

      //把每个键值对转成Node对象,并加入到nodes集合中
      for(Map.Entry<Byte,Integer> entry:counts.entrySet()){
          nodes.add(new Node(entry.getKey(),entry.getValue()));
      }
      return nodes;
  }

  private static Node createHuffmanTree(List<Node> nodes){
      while(nodes.size()>1){
          Collections.sort(nodes);

          Node leftNode=nodes.get(0);
          Node rightNode=nodes.get(1);

          Node parent=new Node(null,leftNode.weight+rightNode.weight);


          parent.left=leftNode;
          parent.right=rightNode;
          nodes.remove(leftNode);
          nodes.remove(rightNode);
          nodes.add(parent);
      }

      //最后的结点就是哈夫曼树的根节点
      return nodes.get(0);

  }

  //前序遍历
    private static void preOrder(Node root){

        if(root==null)
      {
      System.out.println("树为空");
          return;
      }
      else{
          root.preOrder();
      }
    }
}

// 创建Node,存数据和权值
class Node implements Comparable<Node> {
  Byte data; // 存放字符本身
  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();
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值