`
lovinchan
  • 浏览: 31408 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

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: egg.chenlw@gmail.com
 * 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());
}	*/
16
2
分享到:
评论

相关推荐

    数据结构 严蔚敏 赫夫曼编码

    赫夫曼编码是一种高效的数据压缩方法,主要用于无损数据压缩,是数据结构中重要的概念之一。这个主题与著名计算机科学家严蔚敏教授有关,他在数据结构领域的教学和研究上有着深厚的影响力。赫夫曼编码的基本思想是...

    赫夫曼编码译码器

    在“赫夫曼编码译码器”这个小程序中,我们可以理解它具备两个主要功能:编码和解码。编码过程涉及以下步骤: 1. **建立赫夫曼树**:首先,根据输入文件中各个字符的出现频率,创建一个二叉树结构,称为赫夫曼树。...

    用C语言写的赫夫曼编码的(完整)源代码

    赫夫曼编码是一种高效的数据压缩方法,由大卫·赫夫曼在1952年提出。它是基于一种称为“赫夫曼树”(Huffman Tree)的数据结构,用于创建一个可变长度的二进制码,使得频繁出现的字符具有较短的编码,而不常出现的...

    赫夫曼编码的算法实现

    通过阅读和理解这部分内容,你可以深入理解赫夫曼编码的工作原理,并能够编写自己的赫夫曼编码程序。 在实际应用中,赫夫曼编码常被用于文件压缩软件,如早期的LZ77、LZ78压缩算法以及后来的DEFLATE算法(广泛应用...

    赫夫曼编码程序 可以运行

    《构建与理解赫夫曼编码程序》 赫夫曼编码是一种高效的无损数据压缩方法,由赫尔曼·赫夫曼在1952年提出。它的核心思想是利用频率较低的字符用较短的编码,频率较高的字符用较长的编码,从而在总体上减少编码的平均...

    赫夫曼编码,控制台画图

    这个实验不仅涵盖了数据结构和算法的知识,还涉及了程序设计和控制台交互,对于理解赫夫曼编码原理和实现有很好的实践意义。通过亲手实现,你可以深入理解赫夫曼编码的每一个环节,并且掌握如何在有限的资源下,如...

    赫夫曼编码设计

    本次实验的目标是对一篇大约500单词的英文文本文件中的所有字母和标点符号进行统计,计算它们出现的频率,并基于这些频率构建赫夫曼树,进而生成赫夫曼编码。 #### 二、需求分析 根据题目要求,可以将整个项目的...

    赫夫曼编码的应用实验报告,我自己做的,传上来大家一起享用

    5. **性能分析**:实验报告还会对比压缩前后的数据大小,计算压缩比,以证明赫夫曼编码的有效性。此外,可能会讨论时间复杂度和空间复杂度,分析算法的效率。 6. **实验结果与讨论**:这部分会展示实验的具体结果,...

    SFE.rar_sfe_赫夫曼编码

    在“SFE.rar_sfe_赫夫曼编码”这个压缩包中,包含的SFE.txt文件很可能是程序或数据的示例,用于演示如何实现赫夫曼编码。可能的内容包括字符频率表、赫夫曼树的结构或者压缩与解压缩的代码实现。 五、编程实现 在...

    赫夫曼树建立和编码

    - 在这个项目中,可能有一个名为“赫夫曼编码(通过修改txt文件获取不同的编码)”的程序,它可能读取txt文件,计算字符频率,然后根据这些频率动态生成赫夫曼树和相应的编码。 3. **Xcode的使用**: - Xcode是...

    赫夫曼编码(C语言版本)

    3. 遍历所有叶子节点,并计算每个叶子节点的赫夫曼编码,同时将编码结果写入文件。 4. 输出每个字符的赫夫曼编码。 5. 对整个字符串进行编码,并显示编码后的结果。 6. 调用 `unhanffman` 函数解码编码后的字符串,...

    赫夫曼编码解码器-数据库课程设计报告

    在数据库课程设计中,我们可以设计一个数据库来存储字符及其频率信息,以便计算和存储赫夫曼编码。此外,还需要实现编码和解码两个功能。编码过程涉及遍历赫夫曼树,根据左分支记为0,右分支记为1,将字符转换成二...

    赫夫曼树程序(数据结构)

    最后,程序会打印出每个字符的赫夫曼编码,以及赫夫曼树中各节点的详细信息,包括节点的权重、父节点索引和左右孩子索引。 在实际应用中,赫夫曼编码被广泛应用于文件压缩、网络数据传输等领域。例如,著名的ZIP...

    赫夫曼编码译码器的全部源代码(基于C#编码

    3. **生成赫夫曼编码**:从根节点遍历到每个叶子节点,记录路径(左代表0,右代表1),得到每个字符的赫夫曼编码。 4. **编码文本**:根据生成的赫夫曼编码,将文本中的每个字符转换为对应的二进制序列。 解码器...

    赫夫曼树的建立及赫夫曼编码

    总之,赫夫曼树和赫夫曼编码是数据压缩领域的基础工具,它们通过优化编码长度来提高压缩效率,是理解信息论和数据压缩原理的关键概念。在`Huffman.cpp`代码中,我们可以深入学习如何通过编程实现这一过程。

    赫夫曼编解码源码

    在学习这些源码时,可以深入了解如何在实际程序中实现赫夫曼编码和解码的细节,如数据结构的使用(如优先队列)、位操作以及如何有效地存储和重建赫夫曼树。这不仅可以提高编程技能,还能对数据压缩理论有更深入的...

    用赫夫曼编码完成文件压缩--16页.pdf

    总的来说,用赫夫曼编码完成文件压缩涉及到了数据结构(如二叉树)、编码理论(赫夫曼编码)、文件处理和程序设计等多个方面的知识。通过这一过程,可以有效地减少文件占用的存储空间,提高传输效率。

Global site tag (gtag.js) - Google Analytics