【数据结构】-哈夫曼树以及哈夫曼编码

哈夫曼树的几个定义

哈夫曼树又叫最优二叉树:特点是带权路径最短
带权路径长度:该结点到根结点的路径长度乘以该结点的权值。
树的带权路径长度(WPL):所有叶子结点到根结点的带全路径长度之和。

最优二叉树:从已给出的目标带权结点(单独的结点) 经过一种方式的组合形成一棵树.使树的权值最小.。最优二叉树是带权路径长度最短的二叉树。根据结点的个数,权值的不同,最优二叉树的形状也各不相同。它们的共同点是:带权值的结点都是叶子结点。权值越小的结点,其到根结点的路径越长。

哈夫曼树的特点:

  • 权值最大的结点离根结点越近。
  • 没有度为1的结点。
  • 带权路径长度最短。
哈夫曼树的构造以及哈夫曼编码

前缀码:任何一个字符的编码都不是另外一个字符编码的前缀。此种编码为前缀码。
哈夫曼树的构造步骤参见哈夫曼树的构造步骤详解
这篇比较详细的写出了,哈夫曼的构造步骤

哈夫曼树的构造以及哈夫曼编码java实现
package 哈夫曼树与哈夫曼编码;
 
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
 
public class Huffman {
 
	public static class Node<E> {
		E data;
		double weight;
		Node leftChild;
		Node rightChild;
 
		public Node(E data, double weight) {
			super();
			this.data = data;
			this.weight = weight;
		}
 
		public String toString() {
			return "Node[data=" + data + ", weight=" + weight + "]";
		}
	}
 
	public static void main(String[] args) {
		List<Node> nodes = new ArrayList<Node>();
 
		nodes.add(new Node("A", 40.0));
		nodes.add(new Node("B", 8.0));
		nodes.add(new Node("C", 10.0));
		nodes.add(new Node("D", 30.0));
		nodes.add(new Node("E", 10.0));
		nodes.add(new Node("F", 2.0));
		
		Node root = Huffman.createTree(nodes);
		
		System.out.println(breadthFirst(root));
 
	}
 
	private static Node createTree(List<Node> nodes) {
		// 只要nodes数组中还有2个以上的节点
		while (nodes.size() > 1) {
			quickSort(nodes);
			//获取权值最小的两个节点
			Node left = nodes.get(nodes.size()-1);
			Node right = nodes.get(nodes.size()-2);
			
			//生成新节点,新节点的权值为两个子节点的权值之和
			Node parent = new Node(null, left.weight + right.weight);
			
			//让新节点作为两个权值最小节点的父节点
			parent.leftChild = left;
			parent.rightChild = right;
			
			//删除权值最小的两个节点
			nodes.remove(nodes.size()-1);
			nodes.remove(nodes.size()-1);
			
			//将新节点加入到集合中
			nodes.add(parent);
		}
		
		return nodes.get(0);
	}
 
	/**
	 * 将指定集合中的i和j索引处的元素交换
	 * 
	 * @param nodes
	 * @param i
	 * @param j
	 */
	private static void swap(List<Node> nodes, int i, int j) {
		Node tmp;
		tmp = nodes.get(i);
		nodes.set(i, nodes.get(j));
		nodes.set(j, tmp);
	}
 
	/**
	 * 实现快速排序算法,用于对节点进行排序
	 * 
	 * @param nodes
	 * @param start
	 * @param end
	 */
	private static void subSort(List<Node> nodes, int start, int end) {
		if (start < end) {
			// 以第一个元素作为分界值
			Node base = nodes.get(start);
			// i从左边搜索,搜索大于分界值的元素的索引
			int i = start;
			// j从右边开始搜索,搜索小于分界值的元素的索引
			int j = end + 1;
			while (true) {
				// 找到大于分界值的元素的索引,或者i已经到了end处
				while (i < end && nodes.get(++i).weight >= base.weight)
					;
				// 找到小于分界值的元素的索引,或者j已经到了start处
				while (j > start && nodes.get(--j).weight <= base.weight)
					;
 
				if (i < j) {
					swap(nodes, i, j);
				} else {
					break;
				}
			}
 
			swap(nodes, start, j);
 
			//递归左边子序列
			subSort(nodes, start, j - 1);
			//递归右边子序列
			subSort(nodes, j + 1, end);
		}
	}
	
	public static void quickSort(List<Node> nodes){
		subSort(nodes, 0, nodes.size()-1);
	}
	
	//广度优先遍历
	public static List<Node> breadthFirst(Node root){
		Queue<Node> queue = new ArrayDeque<Node>();
		List<Node> list = new ArrayList<Node>();
		
		if(root!=null){
			//将根元素加入“队列”
			queue.offer(root);
		}
		
		while(!queue.isEmpty()){
			//将该队列的“队尾”元素加入到list中
			list.add(queue.peek());
			Node p = queue.poll();
			
			//如果左子节点不为null,将它加入到队列
			if(p.leftChild != null){
				queue.offer(p.leftChild);
			}
			
			//如果右子节点不为null,将它加入到队列
			if(p.rightChild != null){
				queue.offer(p.rightChild);
			}
		}
		
		return list;
	}
}

/*
以上代码中的关键步骤包括:
(1)对list集合中所有节点进行排序;

(2)找出list集合中权值最小的两个节点;

(3)以权值最小的两个节点作为子节点创建新节点;

(4)从list集合中删除权值最小的两个节点,将新节点添加到list集合中

程序采用循环不断地执行上面的步骤,直到list集合中只剩下一个节点,最后剩下的这个节点就是哈夫曼树的根节点
*/
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值