Java版 赫夫曼编码计算程序

package org.rjb.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;

/**
 * 通过输入元素的权值计算出该元素的赫夫曼编码
 * @author LovinChan
 * @version 1.2
 * 
 *   要不是一个我也不知道什么名字的实验课,我也没想到自己动手写这么个丑程序,开始写的
 * 时候还真的遇到了一些困难,主要是对赫夫曼树的数据结构不熟悉,所以刚开始写这个程序的
 * 时候还真的动了一番脑筋,也在网上下了一些代码看了看,可是用我自己的数据测试的时候发
 * 现那些程序很多还是有问题的,于是乎悲剧性的我决定自己写这么个程序,通过输入元素的权
 * 值计算该元素的赫夫曼编码。
 *   权值暂时只能用整数,因为写得比较赶,可能很多地方都没考虑到,希望大家如果发现了错
 * 误能给小弟指正出来,3KS 啦,如果想要跟我交流可以加我的 QQ 或者 MSN:
 * MSN: [email protected]
 * QQ:  372133556(请注明为什么加我)
 * 一个小小的赫夫曼编码Java版算法,希望得到大虾们的点评指导。
 * 
 */
public class HuffmanCode {

	// main method
	public static void main(String[] args) {
		System.out.println("***************    程序开始    ***************");
		HuffmanCode test = new HuffmanCode();
//		test.test();  测试方法
		test.getNodeValue();
		test.caculate();
		test.result();
		System.out.println("***************    程序结束    ***************");
	}
	
	/**
	 * 在命令行获取结点元素值和它的权值
	 */
	public void getNodeValue() {
		// 通过 Scanner 从命令行获得这些值
		Scanner scanner = new Scanner(System.in);
		boolean flag = true;
		while (flag) {
			System.out.println("请输入结点值: (输入 \"-q\" 退出)");
			String value = scanner.next();
			// 输入 -q ,则结束输入
			if (value.equals("-q")) {
				flag = false;
				System.out.println(nodes.size() + " 个结点待编码");
				scanner.close();
				return;
			} else {
				System.out.println("请输入结点权值(整数): ");
				// 权值必须暂必须为整数
				int authority = scanner.nextInt();
				// 构造结点对象
				Node node = new Node(value,authority, "", null, null, null);
				// 添加进待排序结点链表中
				nodes.add(node);
			}
		}
	}
	
	/**
	 * 获得输出结果
	 * 结果有输入结点元素值,权值和它的赫夫曼编码,以及平均码长
	 */
	public void result() {
		int average = 0;
		for (Node node : sortedNodes) {
			System.out.println(node);
			average = average + (node.authority) + node.huffmanCode.length();
		}
		System.out.println("平均码长: " + average);
	}
	
	/**
	 * 先序遍历已排好的赫夫曼树,并把所有的结点加入到一个链表中
	 * @param node 根结点
	 */
	private void preOrder(Node node) {
		if (null != node) {
			nodes.add(node);
			
			// 递归算法
			preOrder(node.leftChild);
			preOrder(node.rightChild);
		}
	}
	
	/**
	 * 计算排好序的赫夫曼树中叶结点的赫夫曼编码,也就是用户输入的结点元素的赫夫曼编码
	 * @param nodes 排好序的赫夫曼树
	 */
	private void setHuffmanCode(List<Node> nodes) {
		for (Node node : nodes) {
			if (null != node.value) {
				// 对每个叶结点,往上遍历到根结点,并顺序记录每个结点的 huffmanCode
				// 最后得到的 huffmanCode 就是该叶结点的赫夫曼编码
				Node parent = node.parent;
				String huffmanCode = node.huffmanCode;
				while (null != parent) {
					huffmanCode = huffmanCode + parent.huffmanCode;
					parent = parent.parent;
				}
				node.huffmanCode = huffmanCode;
				// 将叶结点放到另一个链表中存储起来
				sortedNodes.add(node);
			}
		}
	}


	/**
	 *   将用户输入的元素排列起来,并设计一个赫夫曼树,将根结点存到 unsortedNodes 链表中
	 * 然后通过先序遍历根结点,将每一个结点都存到该链表中,再提取链表中的叶结点,计算得叶
	 * 结点的赫夫曼编码,转存叶结点。
	 */
	public void caculate() {
		
		// nodes 中只剩下一个结点,也就是根结点咯...
		if (nodes.size() == 1) {
			Node node = nodes.get(0);
			// 清空 nodes 链表,删除 nodes 中最后一个元素(根结点)
			nodes.remove(0);
			preOrder(node);
			setHuffmanCode(nodes);
			return;
		}
		
		// 先将传入结点链表按权值排序
		Collections.sort(nodes, new Node());
		
		// 取出前两个元素作为新结点的左右子结点,然后从链表中移除这两个元素
		Node leftChild = nodes.get(0);
		Node rightChild = nodes.get(1);
		
		// 左子树叶子结点总是用户输入的元素之一
		if (null == leftChild.value && null != rightChild.value) {
			Node temp = leftChild;
			leftChild = rightChild;
			rightChild = temp;
		}
		
		nodes.remove(0);
		nodes.remove(0);
		
		/************************  开始计算  ************************/
		/** 排序结果计算每个传入结点的霍夫曼编码 **/
		int authority = leftChild.authority + rightChild.authority;
		
		// 构造父结点,权值为左右子结点的权值和
		Node parent = new Node(null, authority, "", leftChild, rightChild, null);
		
		// 设置左右子结点的 huffmanCode ,左结点为 "0";右结点为 "1"
		leftChild.huffmanCode = leftChild.huffmanCode + "0";
		rightChild.huffmanCode = rightChild.huffmanCode + "1";
		
		// 将子结点的父结点引用指向新创造的父结点
		leftChild.parent = parent;
		rightChild.parent = parent;
		nodes.add(parent);
		caculate();
	}
	
	private List<Node> nodes = new ArrayList<Node>();
	
	public List<Node> sortedNodes = new ArrayList<Node>();
	
	/**
	 * 结点描述
	 * @author LovinChan
	 * @version 1.5
	 */
	class Node implements Comparator<Node> {
		
		public Node() {}
		
		public Node( String value, int authority, String code, Node leftChild, Node rightChild, Node parent) {
			this.huffmanCode = code;
			this.authority = authority;
			this.value = value;
			this.leftChild = leftChild;
			this.rightChild = rightChild;
			this.parent = parent;
		}
		
		// huffmanCode
		String huffmanCode;
		// 权值
		int authority;
		// 值
		String value;
		// 左孩子
		Node leftChild;
		// 右孩子
		Node rightChild;
		// 父结点 
		Node parent;
		
		public String toString() {
			return "元素值: " + value
			+ "\n权值: " + authority
			+ "\nHuffman code: " + huffmanCode ;
		}
		
		@Override // 便于对 List 排序
		public int compare(Node o1, Node o2) {
			if (o1.authority > o2.authority) {
				return 1;
			} else if (o1.authority == o2.authority) {
				if (null == o1.parent && null == o2.parent) {
					return 0;
				} else if (null != o1.parent && null == o2.parent) {
					return -1;
				} else if (null == o1.parent && null != o2.parent) {
					return 1;
				} else {
					return 0;
				}
			} else {
				return -1;
			}
		}
	}
}

/**  测试数据....
 * ***************    程序开始    ***************
请输入结点值: (输入 "-q" 退出)
a
请输入结点权值(整数): 
1
请输入结点值: (输入 "-q" 退出)
b
请输入结点权值(整数): 
2
请输入结点值: (输入 "-q" 退出)
c
请输入结点权值(整数): 
3
请输入结点值: (输入 "-q" 退出)
d
请输入结点权值(整数): 
4
请输入结点值: (输入 "-q" 退出)
e
请输入结点权值(整数): 
5
请输入结点值: (输入 "-q" 退出)
f
请输入结点权值(整数): 
6
请输入结点值: (输入 "-q" 退出)
g
请输入结点权值(整数): 
7
请输入结点值: (输入 "-q" 退出)
-q
**********     程序运行结果    
**********7 个结点待编码
元素值: f
权值: 6
Huffman code: 00
元素值: c
权值: 3
Huffman code: 010
元素值: a
权值: 1
Huffman code: 0110
元素值: b
权值: 2
Huffman code: 1110
元素值: g
权值: 7
Huffman code: 01
元素值: d
权值: 4
Huffman code: 011
元素值: e
权值: 5
Huffman code: 111
平均码长: 7

***************    程序结束    ***************

 */

/*
public void test() {
	Node a = new Node( "a", 5, "", null, null, null);
	Node b = new Node( "b", 29, "", null, null, null);
	Node c = new Node( "c", 7, "", null, null, null);
	Node d = new Node( "d", 8, "", null, null, null);
	Node e = new Node( "e", 14, "", null, null, null);
	Node f = new Node( "f", 23, "", null, null, null);
	Node g = new Node( "g", 3, "", null, null, null);
	Node h = new Node( "g", 11, "", null, null, null);
	unsortedNodes.add(a);		
	unsortedNodes.add(b);
	unsortedNodes.add(c);
	unsortedNodes.add(d);
	unsortedNodes.add(e);
	unsortedNodes.add(f);
	unsortedNodes.add(g);
	unsortedNodes.add(h);
	System.out.println(unsortedNodes.size());
	caculate();
	int average = 0;
	for (Node node : sortedNodes) {
		System.out.println(node);
		average = average + (node.authority) + node.huffmanCode.length();
	}
	
	System.out.println("平均码长: " + average / sortedNodes.size());
}	*/

你可能感兴趣的:(java,C++,c,算法,qq)