Huffman 编码Java实现(贪心算法)

Huffman 编码

问题分析

Java 代码实现

内含详细注释

/*
 * 若尘
 */
package huffmancode;

import java.util.Collections;
import java.util.LinkedList;
import java.util.Scanner;

/**
 * 哈夫曼编码
 * @author ruochen
 * @version 1.0
 */
public class Test {

	/** 用来存放节点值 */
	private static LinkedList<HuffNode> huffList = new LinkedList<HuffNode>();
	
	public static void main(String[] args) {
		// 第一个输入元素个数
		// 然后换行输入 对应权值 元素
		/** 如 
		 * 5
		 * 10 a
		 * 6 b
		 * 4 c
		 * 19 d
		 * 1 e
		 * **/
		System.out.println("Please input: ");
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		for (int i = 0; i < n; i++) {
			huffList.add(new Test().new HuffNode(sc.nextInt(), sc.next()));
		}
		huffmanCode();
		decode(huffList.get(0), "");
	}
	
	class HuffNode implements Comparable<HuffNode> {
		/** 权值 */
		int value;
		String name;
		/** 左孩子节点 */
		HuffNode lChild = null;
		/** 右孩子节点 */
		HuffNode rChild = null;
		
		public HuffNode(int value, String name) {
			this.value = value;
			this.name = name;
		}
		
		public HuffNode(HuffNode lChild, HuffNode rChild) {
			this.lChild = lChild;
			this.rChild = rChild;
			// 权值之和,即合并两个叶子节点
			this.value = lChild.value + rChild.value;
		}
		
		/**
		 * 按照权值大小非递减序列
		 * @param o
		 * @return
		 */
		@Override
	    public int compareTo(HuffNode o) {
	    	if (this.value < o.value) {
	    		return -1;
	    	} else if (this.value == o.value) {
	    		return 0;
	    	} else {
	    		return 1;
	    	}
	    }
	}
	
	/**
	 * 哈夫曼编码
	 */
	public static void huffmanCode() {
		if (huffList.size() == 1) {
			return ;
		}
		while (huffList.size() > 1) {
			// 排序
			Collections.sort(huffList);
			// 将前两个节点进行合并
			HuffNode node = new Test().new HuffNode(huffList.get(0), huffList.get(1));
			// 删除前两个节点
			huffList.remove();
			huffList.remove();
			// 将新生成的节点添加到列表中
			huffList.add(node);
		}
		// 编码完成后,此时huffList中只剩一个根节点
	}
	

	/**
	 * 解码
	 * @param n
	 * @param code
	 */
	public static void decode(HuffNode n, String code) {
		if ((n.lChild == null) && (n.rChild == null)) {
			// 叶子节点, 此时输出其对应编码
			System.out.print(n.name + "--->" + code);
			System.out.println();
			return ;
		}
		// 遍历左子树
		decode(n.lChild, code + "0");
		// 遍历右子树
		decode(n.rChild, code + "1");
		return ;
	}
}

Please input: 
5
10 a
6 b
4 c
19 d
1 e
d--->0
a--->10
e--->1100
c--->1101
b--->111
哈夫曼编码是一种常用的压缩算法,使用贪心算法可以比较简单地实现。 首先需要构建哈夫曼树,然后根据哈夫曼树生成对应的哈夫曼编码。具体实现步骤如下: 1. 定义一个节点类Node,包含字符ch、权值weight、左右子节点left和right等属性。 2. 定义一个哈夫曼树类HuffmanTree,包含根节点root,以及构建哈夫曼树的方法buildTree。 3. 构建哈夫曼树的方法buildTree,接收一个字符数组chars,返回一个哈夫曼树。 a. 计算每个字符出现的频率,并将每个字符和其对应的频率保存在一个Map中。 b. 将Map中的所有节点按照权值从小到大排序,并将节点放入一个优先队列中。 c. 从优先队列中取出两个权值最小的节点作为左右子节点,生成一个新的父节点,并将其放回优先队列中。 d. 重复c的操作,直到优先队列只剩下一个节点,此节点即为哈夫曼树的根节点。 4. 定义一个编码HuffmanCode,包含一个编码表Map,以及生成编码的方法generateCodes。 5. 生成编码的方法generateCodes,接收一个哈夫曼树,并返回一个编码表。 a. 如果节点是叶子节点,则将其编码加入编码表中。 b. 如果节点有左右子节点,则将左子节点的编码加上字符'0',将右子节点的编码加上字符'1',并分别递归处理左右子节点。 6. 最后可以使用生成的编码表对原始字符串进行编码,将每个字符替换为对应的编码即可。 下面是Java代码实现: ``` import java.util.*; class Node { char ch; int weight; Node left; Node right; public Node(char ch, int weight) { this.ch = ch; this.weight = weight; } } class HuffmanTree { Node root; public HuffmanTree(Node root) { this.root = root; } public static HuffmanTree buildTree(char[] chars) { Map<Character, Integer> freq = new HashMap<>(); for (char ch : chars) { freq.put(ch, freq.getOrDefault(ch, 0) + 1); } PriorityQueue<Node> pq = new PriorityQueue<>((a, b) -> a.weight - b.weight); for (Map.Entry<Character, Integer> entry : freq.entrySet()) { pq.offer(new Node(entry.getKey(), entry.getValue())); } while (pq.size() > 1) { Node left = pq.poll(); Node right = pq.poll(); Node parent = new Node('\0', left.weight + right.weight); parent.left = left; parent.right = right; pq.offer(parent); } return new HuffmanTree(pq.poll()); } } class HuffmanCode { Map<Character, String> codes = new HashMap<>(); public HuffmanCode(HuffmanTree tree) { generateCodes(tree.root, ""); } private void generateCodes(Node node, String code) { if (node.left == null && node.right == null) { codes.put(node.ch, code); return; } generateCodes(node.left, code + "0"); generateCodes(node.right, code + "1"); } public String encode(String str) { StringBuilder sb = new StringBuilder(); for (char ch : str.toCharArray()) { sb.append(codes.get(ch)); } return sb.toString(); } public String decode(String code) { StringBuilder sb = new StringBuilder(); Node node = HuffmanTree.root; for (char bit : code.toCharArray()) { node = (bit == '0') ? node.left : node.right; if (node.left == null && node.right == null) { sb.append(node.ch); node = HuffmanTree.root; } } return sb.toString(); } } public class Main { public static void main(String[] args) { char[] chars = "ABRACADABRA".toCharArray(); HuffmanTree tree = HuffmanTree.buildTree(chars); HuffmanCode code = new HuffmanCode(tree); String encoded = code.encode("ABRACADABRA"); System.out.println(encoded); System.out.println(code.decode(encoded)); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

若尘

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

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

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

打赏作者

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

抵扣说明:

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

余额充值