霍夫曼编码

关于字符串的一些算法的github
https://github.com/fuzekun/MyAlgorithm

使用IDEA写的,jdk8.0以及以上就可运行,就是写算法的,用不到其他的外部依赖

用图片说话

在这里插入图片描述

流程

<一>编码实现
1.建立哈夫曼树
(1)统计叶子节点(每个字符)的权重
(2)初始化优先队列
(3)依次找到队列中最小和次小的节点,创建新节点作为这两个节点父节点,权重为两个父节点的和,然后放入有限队列中,直到队列中还有一个节点,这个就是根节点

2.建立编码表
(1)递归前序遍历哈夫曼树
(2)左子树编码为0,右子树编码为1
(3)如果是叶子节点,使用映射保存叶子节点字符的编码。

3.将树保存为比特流
(1)递归的前序遍历树,如果是叶子节点,保存标志1,并且将叶子对应的字符保存为八位2进制,返回
(2)如果不是叶子节点,保存标志0

4…实现字符串编码
再次遍历一遍输入流,从映射中找到每个字符对应的哈夫曼编码,保存下来

<二>解码实现
1.读取汉夫曼树
(1)递归前序遍历树,如果是叶子节点,放回一个新的叶子节点(没有左右子树)
(2)否则返回一个新的根节点(左右子树递归遍历比特流)
2.将编码通过树解码
遍历剩下的比特流(字符串的编码),根据得到的哈夫曼树,得到具体的字符
如果是叶子节点,输出字符
否规是0遍历左子树,是1遍历右子树

实现

用到了优先队列具体的代码在github中,这里只有哈夫曼的代码,如果想完整的运行,请下载我github中代码,不用配置直接运行。

package 字符串;

import dataStructure.MinPQ;

import java.io.*;
import java.util.ArrayList;

//哈夫曼编码实现数据压缩
public class Huffman {
    private static int R = 256;                                    //字母表的大小,2^8
    private static String file = "";                              //写入文件的内容,为哈夫曼编码
    private static String tree = "";                              //二进制的哈夫曼树
    private static ArrayList<String> codings = new ArrayList<>();//字符的编码
    private static int pos = -1;                                 //读取编码树时候所需要的位置信息
    private static class Node implements Comparable<Node>{
        private char ch;
        private int freq;
        private final Node left,right;

        public Node(char ch,int freq,Node left,Node right){
            this.ch = ch;
            this.freq = freq;
            this.left = left;
            this.right = right;
        }
        public boolean isleaf(){
            return left == null && right == null;
        }
        public int compareTo(Node other){
            return this.freq - other.freq;
        }
    }

    //扩展编码,还原原来的字符串
    public static void expand(){
        char[] filen = file.toCharArray();
        System.out.println("读取树:");
        Node root = readTrie(tree.toCharArray());
        System.out.println();
        int i = tree.length();
        String ans = "";
        while( i < filen.length){
            Node x = root;
            while(!x.isleaf()){
                if(filen[i++] == '0'){
                    x = x.left;
                }
                else x = x.right;
            }
            ans += x.ch;
            System.out.print(x.ch);
        }
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(new File("hufen.txt")));
            writer.write(ans);
            writer.close();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }

    //编码
    public static String[] buildCode(Node root){
        //使用单词查找树构造编译表
        String[] st = new String[R];
        buildCode(st,root,"");
        return st;
    }
    public static void buildCode(String[] st,Node x,String s){
        //使用单词查找树构造编译表
        if(x.isleaf()){
            st[x.ch] = s;return ;
        }
        buildCode(st,x.left,s + '0');
        buildCode(st,x.right,s + '1');
    }

    //打印编译树
    public static void printTree(Node root){
        if(root.isleaf()){
            System.out.println(root.ch);
            return ;
        }
        printTree(root.left);
        printTree(root.right);
    }

    //建立编译树
    private static Node buildTrie(int[] freq){
        //使用多棵单节点树初始化优先队列
        MinPQ<Node>pq = new MinPQ<>(100);
        for(char c = 0; c < R; c++){
            if(freq[c] > 0){
                pq.insert(new Node(c,freq[c],null,null));
            }
        }
//        for(Node node : pq){
//            System.out.println(node.ch);
//        }
        while(pq.size() > 1){
            Node x = pq.delMin();
            Node y = pq.delMin();
            Node parent = new Node('\0',x.freq + y.freq, x, y);
            pq.insert(parent);
        }
        Node root = pq.delMin();
        return root;
    }

    //将编译树转化成比特流
    private static void writeTrie(Node x){
        if(x.isleaf()){
            //1.叶子节点写1加上8位ascii码
            tree +=  '1';
            String tmp = Integer.toBinaryString((int)x.ch);
            //转换成ASCII码,八位
            for(int i = tmp.length(); i < 8; i++){
                tmp = '0' + tmp;
            }
            tree += tmp;
            return;
        }
        //2.非叶子节点写0
        tree += '0';
        //3.递归建立
        writeTrie(x.left);
        writeTrie(x.right);
    }

    //读取编译树
    private static Node readTrie(char[] file){
        pos++;
        //从文件中读入字符串
       if(file[pos] == '1'){//叶子节点
           System.out.print(1);
           int x = 0;
           for(int i = 0; i < 8; i++){
               x = x * 2 + file[++pos] - '0';
               System.out.print(file[pos]);
           }
           System.out.print(" ");
           return new Node((char)x,0,null,null);
       }
       System.out.print(file[pos]);
       return new Node('\0',0,readTrie(file),readTrie(file));
    }

    //压缩
    public static void compress(String s) {
        char[] input = s.toCharArray();
        //1.统计频率
        int[] freq = new int[R];
        for(int i = 0; i < input.length; i++){
            freq[input[i]]++;
        }

        //2.构造霍夫曼编码树
        Node root = buildTrie(freq);

        //3.构造编译表
        String[] st ;
        st = buildCode(root);

        //4.打印解码用的单词查找树
        writeTrie(root);

//        //5.打印字符总数
//        int n = input.length;
//        file += Integer.toBinaryString(n);

        //必要的打印,帮助理解
        System.out.println("单词查找树为");
        System.out.println(tree);
        System.out.println("各个字符的编码是:");
        for(int i = 0; i < st.length; i++){
            if(st[i] != null && st[i].compareTo("") != 0)System.out.println((char)i + " : " + st[i]);
        }
        System.out.println("字符串的编码是:");
        //使用霍夫曼编码处理输入
        for(int i = 0; i < input.length; i++){
            String code = st[input[i]];
            System.out.print(code);
            codings.add(code);
        }
        System.out.println();
        System.out.println("哈夫曼编码是:");
        file = tree;
        for(String stt : codings){
            file += stt;
        }
        System.out.println(file);
        //6.将编码写入文件
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(new File("huf.txt")));
            writer.write(file);
            writer.close();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }

    public static void main(String[] args) {
//        Huffman huffman = new Huffman();
//        huffman.compress("ABRACADABRA!");
//        huffman.expand();
        Huffman.compress("I am happy today");
        System.out.println("解码是:");
        Huffman.expand();
    }
}

性能分析

(1)适用于给定的字符串,对于任意长度的字符串无法处理。
(2)字符串的中字符的重复越多,性能越好,字符
(3)字符数组的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值