ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

哈夫曼树

2019-07-01 15:27:10  阅读:154  来源: 互联网

标签:Node node 哈夫曼 int que 权值 节点


哈夫曼树:

  当树中的节点被赋予一个表示某种意义的数值,我们称之为该节点的权。从树的根节点到任意节点的路径长度(经过的边数)与该节点上权值的乘积称为该节点的带权路径长度。树中所有叶节点的带权路径长度之和称为该树的带权路径长度(WPL)。当带权路径长度最小的二叉树被称为哈夫曼树,也成为最优二叉树。

哈夫曼树的构造:

  哈夫曼树在构造时每次从备选节点中挑出两个权值最小的节点进行构造,每次构造完成后会生成新的节点,
将构造的节点从备选节点中删除并将新产生的节点加入到备选节点中。新产生的节点权值为参与构造的两个节点权值之和。

构造哈夫曼树的算法:

1)对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。

2)在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。

3)从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。

4)重复2)和3),直到集合F中只有一棵二叉树为止。

下面来看代码:

public class HaffManCode {

	private static class Node implements Comparable<Node> {
		// 权值
		int val;
		// 左节点
		Node left;
		// 右节点
		Node right;

		public Node(int val) {
			this.val = val;
		}

		@Override
		public int compareTo(Node o) {
			return this.val - o.val;
		}
	}

	/**构造哈夫曼树
	 * @param W 权值数组
	 * @return
	 */
	public Node createHaffManTree(int[] W) {
		// 通过堆来实现自动动态排序
		PriorityQueue<Node> heap = new PriorityQueue<Node>();
		for (int e : W) {
			heap.offer(new Node(e));
		}
		while (heap.size() > 1) {
			// 每次取权值最小的两个节点构建一个新的父节点且新节点参与到新的一轮构建中
			Node min1 = heap.poll();
			Node min2 = heap.poll();
			Node parent = new Node(min1.val + min2.val);
			parent.left = min1;
			parent.right = min2;
			heap.offer(parent);
		}
		return heap.poll();
	}
    // 打印树
	public void showTree(Node t) {
		int level = countLevel(t);
		countLevel(t);
		LinkedList<Node> que = new LinkedList<>();
		que.add(t);
		int curLevel = 1;
		while (!que.isEmpty() && curLevel <= level) {
			int len = que.size();
			// 每行左边所需空格数
			int space_num = (int) (Math.pow(2, level - curLevel)) - 1;
			// 左边的空格
			while (space_num >= 1) {
				System.out.print(" ");
				space_num--;
			}
			for (int i = 0; i < len; i++) {
				Node node = que.poll();
				// 每行节点间的空格数
				int between_e_space = (int) Math.pow(2, level + 1 - curLevel) - 1;
				// 空节点
				if (node.val == Integer.MIN_VALUE) {
					System.out.print(" ");
				} else {
					System.out.print(node.val);
				}
				while (between_e_space >= 1) {
					System.out.print(" ");
					between_e_space--;
				}
				if (node != null) {
					if (node.left == null) {
						// 空占位节点
						que.add(new Node(Integer.MIN_VALUE));
					} else {
						que.add(node.left);
					}
					if (node.right == null) {
						que.add(new Node(Integer.MIN_VALUE));
					} else {
						que.add(node.right);
					}
				}
			}
			// 换行
			System.out.println();
			curLevel++;
		}

	}
    // 计算树的高度
	private static int countLevel(Node t) {
		if (t == null)
			return 0;
		LinkedList<Node> que = new LinkedList<>();
		que.add(t);
		int level = 0;
		while (!que.isEmpty()) {
			level++;
			int len = que.size();
			for (int i = 0; i < len; i++) {
				Node node = que.poll();
				if (node != null) {
					if (node.left != null)
						que.offer(node.left);
					if (node.right != null)
						que.offer(node.right);
				}
			}
		}
		return level;
	}

	public static void main(String[] args) {
		HaffManCode haffMan = new HaffManCode();
		int[] w = { 7, 5, 2, 4 };
        haffMan.showTree(haffMan.createHaffManTree(w));
	}
}

 应用: 在处理字符串序列时,如果对每个字符串采用相同的二进制位来表示,则称这种编码方式为定长编码。若允许对不同的字符采用不等长的二进制位进行表示,那么这种方式称为可变长编码。 可变长编码其特点是对使用频率高的字符采用短编码,而对使用频率低的字符则采用长编码的方式。这样我们就可以减少数据的存储空间,从而起到压缩数据的效果。而通过哈夫曼树形成的哈夫曼编码是一种的有效的数据压缩编码。 

 

标签:Node,node,哈夫曼,int,que,权值,节点
来源: https://blog.csdn.net/sinat_22808389/article/details/94392250

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有