《算法导论》第16章贪心算法赫夫曼编码java实现

1.字符结点类CharNode,用于封装一个字符的值和它出现的频率

CharNode.java

//字符结点类,用于封装一个字符的值和它出现的频率
public class CharNode {
	private char c;
	private int freq;
	public CharNode(char c, int freq) {
		this.c = c;
		this.freq = freq;
	}
	public char getC() {
		return c;
	}
	public void setC(char c) {
		this.c = c;
	}
	public int getFreq() {
		return freq;
	}
	public void setFreq(int freq) {
		this.freq = freq;
	}
    
	public String toString() {
		return "字符:"+this.c+",出现频率:"+this.freq;
	}
}

2.赫夫曼树的结点类Node,对应书中的Node,用于将字符转换为符合赫夫曼树中的Node类。

除了和书中一样的属性外,为了保证编码搜索路径显示的方便,Node类增加了一个属性标记信号sign,只有两个值:0或1,若在构建赫夫曼二叉树的过程中该节点为左节点,则sign=0,反之,sign=1

Node.java

//赫夫曼树的结点类,用于字符转换为Node
public class Node implements Comparable<Node>{
	
	private char charValue;//保存了字符值
	private int freq;//保存字符出现的频率
	private Node left;//左子节点
	private Node right;//右子节点
	
	private int sign;//标记信号,只有两个值:0或1,若在构建赫夫曼二叉树的过程中该节点为左节点,则sign=0,反之,sign=1
	
	public Node() {
		
	}
	
	public Node(CharNode charnode) {
		this.charValue = charnode.getC();
		this.freq = charnode.getFreq();
		this.sign = 0;//初始化的结点sign都是0
	}
	
	public char getCharValue() {
		return this.charValue;
	}
	
	public void setCharValue(char charValue) {
		this.charValue = charValue;
	}
	
	public int getFreq() {
		return this.freq;
	}
	
	public void setFreq(int freq) {
		this.freq = freq;
	}
	
	public Node getLeft() {
		return this.left;
	}
	
	public void setLeft(Node left) {
		this.left = left;
	}
	
	public Node getRight() {
		return this.right;
	}
	
	public void setRight(Node right) {
		this.right = right;
	}
	
	
	
	public int getSign() {
		return sign;
	}

	public void setSign(int sign) {
		this.sign = sign;
	}

	@Override
	public int compareTo(Node newNode) {
		if(this.freq==newNode.freq) {
			return 0;
		}else if(this.freq<newNode.freq){
			return -1;
		}else {
			return 1;
		}
	}

	
}

3.书中HUFFMAN(C)的实现:使用PriorityQueue最小优先队列实现

    //1.得到最终的二叉树后,就可以进行编码了,依次遍历二叉树的每一条路径,取每个节点的sign值,
    //2.遍历到叶结点后,叶结点charValue值所对应的的路径去除第一个字符即为该字符的编码
    //3.例如假如第一个叶结点对应的字符为b,对应的路径为00000,去除第一个字符后,可得最终编码为0000

HuffMan.java

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.PriorityQueue;



public class HuffMan {
	
	public static void main(String[] args){
		CharNode[] C = {new CharNode('a', 45),
						new CharNode('b', 13),
						new CharNode('c', 12),
						new CharNode('d', 16),
						new CharNode('e', 9),
						new CharNode('f', 5)}; 
		for(CharNode c:C) {
			System.out.println(c.toString());
		}
		
		//获取huffman树的根节点
		Node root = Huffman(C);
		Map<Character, String> map = new HashMap<Character,String>();
		findPath(root, map, new StringBuilder());
		System.out.println("字符编码信息为:");
		PrintCharEncoderList(map);
	}
	
	//构建Huffman树的方法,返回huffman树的根节点
	public static Node Huffman(CharNode[] CSet) {
		int n = CSet.length;
		Node[] huffmanNodeArray = new Node[n];
		for(int i=0;i<n;i++) {
			huffmanNodeArray[i] = new Node(CSet[i]);
		}
		PriorityQueue<Node> Q = new PriorityQueue<Node>(n);
		for(int i=0;i<n;i++) {
			Q.add(huffmanNodeArray[i]);
		}
		for(int i=0;i<n-1;i++) {
			Node z = new Node();
			Node x = Q.poll();
			x.setSign(0);//因为x是左节点,所以x的sign信号值是0
			z.setLeft(x);
			Node y = Q.poll();
			y.setSign(1);//因为y是右节点,所以y的sign信号值是1
			z.setRight(y);
			z.setFreq(x.getFreq()+y.getFreq());
			Q.add(z);
		}
		return Q.poll();
	}
	
	
	//1.得到最终的二叉树后,就可以进行编码了,依次遍历二叉树的每一条路径,取每个节点的sign值,
	//2.遍历到叶结点后,叶结点charValue值所对应的的路径去除第一个字符即为该字符的编码
	//3.例如假如第一个叶结点对应的字符为b,对应的路径为00000,去除第一个字符后,可得最终编码为0000
    
	//遍历获取每个字符的编码值
	public static void findPath(Node root, Map<Character,String> map, StringBuilder path) {
        //path是记录了路径,每插入一个结点的Sign值后,删除path中最后一个值,map中存放每个字符对应的编码值
		if (root.getLeft()== null && root.getRight() == null) {
            path.append(root.getSign());
            map.put(root.getCharValue(),path.substring(1));//
            path.deleteCharAt(path.length() - 1);
            return;
        }
        path.append(root.getSign());
        if (root.getLeft() != null) findPath(root.getLeft(), map, path);
        if (root.getRight() != null) findPath(root.getRight(), map, path);
        path.deleteCharAt(path.length() - 1);
    	
        
    } 
    
	//打印编码的信息
    public static void PrintCharEncoderList(Map<Character,String> map) {
    	Character key = null;
    	String value = null;
    	Iterator it = map.entrySet().iterator();
    	while(it.hasNext()) {
    		Map.Entry<Character,String> entry = (Entry) it.next();
    		key = entry.getKey();
    		value = entry.getValue();
    		System.out.println("字符:"+key+",编码:"+value);
    	}
    }
}

书中例子:

对应的赫夫曼树:

代码结果:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值