`
felixour
  • 浏览: 31715 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类
最新评论

Netjava Lesson 16 重温旧识——哈夫曼树

阅读更多

2013.09.24

 

今天我们来重温一下以前学习的关于哈夫曼树的构建。

 

回顾一下,我们给定了一些节点,每个节点都有对应的数值,现在我们要用这些节点生成二叉树,而且要求加权路径最小,即权值乘以节点对应的数值,然后再求和,我们要求的是这个最小。比如我们现在有64个节点,要是按照平时,我们会将64个节点一字排开,然后两两生成父节点,然后父节点再生父节点,直至生成以二叉树。但是这样的话我们显然可以看出加权路径不是最优的,因为大数值点和小数值点在一个水平上。我们如果要实现加权路径最小,那么我们就更希望小数值节点在下面,而大数值节点在上面。哈夫曼树的构建正是基于这一原理,实现了对字符串的压缩,进而可以去实现对于文件的压缩。

 

在进行压缩前,我们先定义一个节点类:

public class Node {
	Node left;//左节点
	Node right;//右节点
	char ch;//节点对应的字符
	int num;//数值
}

 

还有就是编码类:

public class Code {
	private char ch;// 字符
	private int num;// 出现次数
	private String str;// 对应编码
}

 

当然基础类还会有构造方法和get,set方法,我们这里就不一一阐述了。

 

然后我们就要来构建哈夫曼树:
首先我们定义两个队列:

ArrayList<Code> code = new ArrayList<Code>();
ArrayList<Node> node = new ArrayList<Node>();

code用于存放编码,node用于存放节点。

 

下面我们就要开始进行哈夫曼树的构建了:
1、我们要开始字符串的统计,并将字符和其出现次数生成编码存到编码队列里:

	public void countString(String str) {
		char[] ch = str.toCharArray();
		for (int i = 0; i < ch.length; i++) {
			boolean bol = true;
			for (int j = 0; j < code.size(); j++) {
				if (ch[i] == code.get(j).getCh()) {
					code.get(j).setNum(code.get(j).getNum() + 1);
					bol = false;
				}
			}
			if (bol) {
				code.add(new Code(ch[i]));
			}
		}
	}

 

2、创建哈夫曼树:

	public void creatTree() {
		for (int i = 0; i < code.size(); i++) {
			node.add(new Node(code.get(i).getCh(), code.get(i).getNum()));// 将叶子节点输入
		}
		sortNode();// 进行编码排序
		while (node.size() > 1) {
			Node temp = new Node(node.get(0), node.get(1), node.get(0).getNum()
					+ node.get(1).getNum());
			node.remove(0);
			node.remove(0);
			node.add(temp);
			sortNode();
		}
	}

 

 其中用到sortNode方法,是用来对节点对应的数值进行一个排序:

	private void sortNode() {
		for (int i = 0; i < node.size(); i++) {
			for (int j = i; j < node.size(); j++) {
				if (node.get(i).getNum() > node.get(j).getNum()) {
					Node node1 = node.get(i);
					Node node2 = node.get(j);
					node.set(i, node2);
					node.set(j, node1);
				}
			}
		}
	}

 

3、根据节点生成码表:

	public void creatCodeList() {
		String str = new String();
		codeList(node.get(0), str);
		for (int i = 0; i < code.size(); i++) {
			System.out.println(code.get(i).getCh() + "   "
					+ code.get(i).getStr());
		}
	}

 

这里我们用递归来生成码表,写了codeList方法:

	private void codeList(Node node, String str) {
		if (node.left == null && node.right == null) {
			for (int i = 0; i < code.size(); i++) {
				if (code.get(i).getCh() == node.getCh()) {
					code.get(i).setStr(str);
				}
			}
		}
		if (node.left != null) {
			codeList(node.left, str + "0");
		}
		if (node.right != null) {
			codeList(node.right, str + "1");
		}
	}

 

4、根据码表生成最终编码:

	public String printCodeList(String s) {
		char[] ch = s.toCharArray();
		String str = new String();
		for (int i = 0; i < ch.length; i++) {
			for (int k = 0; k < code.size(); k++) {
				if (code.get(k).getCh() == ch[i]) {
					str += code.get(k).getStr();
					break;
				}
			}
		}
		System.out.println(str);
		return str;
	}

 

5、根据码表和生成的编码还原编码:

	public String restoreCodeList(String codeStr) {
		String str = new String();
		for (int i = 0; i < codeStr.length(); i++) {
			for (int j = i; j <= codeStr.length(); j++) {
				String temp = codeStr.substring(i, j);
				for (int k = 0; k < code.size(); k++) {
					if (code.get(k).getStr().equals(temp)) {
						str += code.get(k).getCh();
						i = j;
					}
				}
			}
		}
		System.out.println(str);
		return str;
	}

 

这样,哈夫曼树的构建就完成了,下一次我们就会讲如何利用哈夫曼树实现文件的压缩,敬请期待~

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics