哈夫曼编码(Java)

class Node {
    int weight; // 权重
    int left; // 当前节点的左孩子
    int right; // 当前节点的右孩子
    int parent; // 当前节点的父结点
    
    public Node() {}
}

public class Huffman {
    static Scanner sc = new Scanner(System.in);

    // 获得 hfTree[1...len] 权值最小且没有父结点的两个节点的下标
    public static int[] getMin(int len){
        int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
        int pos1 = -1, pos2 = -1;
        for(int i = 1; i <= len; i++){
            if (hfTree[i].parent == 0) { // parent!=0 说明当前节点已经放到哈夫曼树中了
                if(hfTree[i].weight < min1){
                    min2 = min1;
                    pos2 = pos1;
                    min1 = hfTree[i].weight;
                    pos1 = i;
                }else if(hfTree[i].weight < min2){
                    min2 = hfTree[i].weight;
                    pos2 = i; 
                }
            }
        }
        return new int[]{pos1, pos2};
    }
    
    static Node[] hfTree;
    // 将 n 个节点组成一棵哈夫曼树,需要经过 n-1 次合并,并且该哈夫曼树中有 2n-1 个节点
    public static void createHuffmanTree(int n){
        int m = 2 * n - 1; // 哈夫曼树中有 2 * n - 1 个节点
        hfTree = new Node[m + 1]; // 0 号位置不用
        for(int i = 1; i <= m; i++) hfTree[i] = new Node();
        // 初始化 n 个节点的信息
        for(int i = 1; i <= n; i++){
            hfTree[i].weight = sc.nextInt();
            hfTree[i].left = hfTree[i].right = 0;
            hfTree[i].parent = 0;
        }


        // 哈夫曼树一共有 2n-1 个节点,初始时有 n 个节点,存放在 [1-n] 号位置,
        // 新生成的节点存放在 [n+1~m] 号位置
        for(int i = n + 1; i <= m; i++){
            // 获得 hfTree[1...i-1] 中权值最小且没有父结点的两个节点的下标
            int[] temp = getMin(i - 1);
            int minPos1 = temp[0], minPos2 = temp[1];
            // 下标为 minPos1 的节点和下标为 minPos2 的节点合并成了新的节点
            hfTree[minPos1].parent = hfTree[minPos2].parent = i;
            hfTree[i].weight = hfTree[minPos1].weight + hfTree[minPos2].weight;
            hfTree[i].left = minPos1;
            hfTree[i].right = minPos2;
        }
    }

    // 获得 n 个字符的编码
    public static String[] enCode(int n){
        String[] codes = new String[n + 1]; // 不使用 0 号位置
        Arrays.fill(codes, "");

        // 哈夫曼树的根是在最后一个位置
        for(int i = 1; i <= n; i++){
            int cur = i; // 当前节点
            int parent = hfTree[i].parent; // 当前节点的父结点
            // 哈夫曼树根节点没有父结点,其 parent 值为 0
            while(parent != 0){
                // 如果当前节点是其父结点的左孩子,编码为 '0'
                if(hfTree[parent].left == cur){
                    codes[i] = "0" + codes[i]; 
                }else { // 如果当前节点是其父结点的右孩子,编码为 '1'
                    codes[i] = "1" + codes[i];
                }
                // 让父结点成为新的孩子结点,继续朝树根的方向遍历
                cur = parent;
                parent = hfTree[cur].parent;
            }
        }
        return codes;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

静波波呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值