乐趣区

关于java:赫夫曼编码数据压缩算法

赫夫曼算法类 Huffman.java
/**

  • @Author: ltx
  • @Description: 赫夫曼编码
    */

public class Huffman {

Map<Character, String> codeMap = new HashMap<>();
/**
 * 中序遍历 (前序或后序也行)
 * 失去 huffman 编码
 *
 * @param node 节点
 * @param sb   StringBuilder
 */
public void getCodeByMidOrder(Node node, StringBuilder sb) {if (node.left != null) {
        // 往左走 +'0'
        sb.append("0");
        getCodeByMidOrder(node.left, sb);
    }
    // 叶子节点
    if (node.left == null && node.right == null) {

// System.out.print(node + “:” + sb + “, “);

        codeMap.put(node.value, sb.toString());
    }
    if (node.right != null) {
        // 往右走 +'1'
        sb.append("1");
        getCodeByMidOrder(node.right, sb);
    }
    // 回溯向上走缩小一个字符
    if (sb.length() > 0) {sb.deleteCharAt(sb.length() - 1);
    }
}
public Node getHuffmanTree(List<Node> nodes) {Collections.sort(nodes);

// System.out.println(nodes);

    while (nodes.size() > 1) {
        // 左叶子 - 数组最小值
        Node leafLeft = nodes.remove(0);
        // 右叶子 - 数组次小值
        Node leafRight = nodes.remove(0);
        // 父节点 = 数组最小值 + 数组次小值
        Node parentNode = new Node(null, leafLeft.weight + leafRight.weight);
        parentNode.left = leafLeft;
        parentNode.right = leafRight;
        // 新的节点增加到 list 外面
        nodes.add(parentNode);
        Collections.sort(nodes);
    }
    return nodes.get(0);
} 
/**
 * 获取各个字符权重 (字符个数)
 *
 * @param str
 * @return
 */
public List<Node> getCharWight(String str) {Map<Character, Integer> charNumMap = new HashMap<>();
    char[] chs = str.toCharArray();
    for (char c : chs) {
        // 数量
        Integer count = charNumMap.get(c);
        if (count == null) {charNumMap.put(c, 1);
        } else {charNumMap.put(c, count + 1);
        }
    }

// System.out.println(charNumMap);

    List<Node> nodes = new ArrayList<>();
    // 创立节点 List
    for (char c : charNumMap.keySet()) {nodes.add(new Node(c, charNumMap.get(c)));
    }
    return nodes;
} 
/**
 * 编码
 * 依据赫夫曼编码表,对原始数据做转换
 *
 * @param str 原始字符串
 * @return
 */
public String encoding(String str) {StringBuilder sb = new StringBuilder();
    char[] chs = str.toCharArray();
    for (char c : chs) {sb.append(codeMap.get(c));
    }
    return sb.toString();} 
/**
 * 解码
 *
 * @return
 */
public String decode(String encodStr) {
    // 翻转 codeMap
    Map<String, Character> encodeMap = new HashMap<>();
    for (char c : codeMap.keySet()) {encodeMap.put(codeMap.get(c), c);
    }
    char[] chs = encodStr.toCharArray();
    int j = 0;
    StringBuilder res = new StringBuilder();
    while (j < encodStr.length() - 1) {StringBuilder sb = new StringBuilder();
        Character cr;
        // 匹配出字符串
        while ((cr = encodeMap.get(sb.toString())) == null) {sb.append(chs[j]);
            j++;
        }
        res.append(cr);
    }
    return res.toString();}
public static void main(String[] args) {Huffman huffman = new Huffman();
    System.out.println("原始数据:");
    // 须要压缩的串
    String str = "i like like like java do you like a java";
    System.out.println(str);
    //1. 取得字符权重 List
    List<Node> nodes = huffman.getCharWight(str);
    //[:9, a:5, d:1, e:4, u:1, v:2, i:5, y:1, j:2, k:4, l:4, o:2]
    System.out.println("节点权重列表:");
    System.out.println(nodes);
    //2.[PerfectMoney 下载](https://www.gendan5.com/wallet/PerfectMoney.html) 结构赫夫曼树
    Node root = huffman.getHuffmanTree(nodes);
    //3. 取得赫夫曼编码表
    huffman.getCodeByMidOrder(root, new StringBuilder(""));
    System.out.println("赫夫曼编码表:");
    // 失去赫夫曼编码表
    //{=01, a=100, d=11000, u=11001, e=1110, v=11011, i=101, y=11010, j=0010, k=1111, l=000, o=0011}
    System.out.println(huffman.codeMap);
    //4. 压缩编码
    String encodStr = huffman.encoding(str);
    System.out.println("压缩后数据:");

//1010100010111111110010001011111111001000101111111100100101001101110001110000011011101000111100101000101111111100110001001010011011100

    System.out.println(encodStr);
    //5. 解压
    String res = huffman.decode(encodStr);
    System.out.println("解压后数据:");
    // 打印最终后果
    //i like like like java do you like a java
    System.out.println(res);
}

}

退出移动版