什么是霍夫曼树
霍夫曼树是二叉树的一种特殊形式,又称为最优二叉树,其主要作用在于数据压缩和编码长度的优化。
给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为霍夫曼树(Huffman Tree)。
霍夫曼树的构造思路
若要使得带权外路径长度最小,可以将权值大的节点尽量靠近根节点,这样路径短一些;而权值小的节点可以适当远离根节点,因为权值小,外路径稍微长一点也没事。
应用场景
- 霍夫曼编码
霍夫曼编码是一种基于最小冗余编码的压缩算法。最小冗余编码是指,如果知道一组数据中符号出现的频率,就可以用一种特殊的方式来表示符号从而减少数据需要的存储空间。一种方法是使用较少的位对出现频率高的符号编码,用较多的位对出现频率低的符号编码。我们要意识到,一个符号不一定必须是文本字符,它可以是任何大小的数据,但往往它只占一个字节。
算法题应用
霍夫曼树的特性除了压缩,还可以用于一些关于最小代价问题的决策上。
例如:一个老木匠,有若干段长短不一的木头,他想把这些木头全部拼成一根,每次拼接耗费的体力是当前拼接的两段木头的长度,问老木匠最小花费多少体力。
代码实现
- 利用优先队列存储节点,保证队列中的节点值是有序的;
- 每次获取队列中的两个最小值,然后用这两个节点的和构造一个新的节点作为它们的父节,然后子节点出队,父节点入队;
- 循环这个过程,直到队列中只有一个节点为止,返回这个节点即可。
TreeNode hfmTree(int[] w){
// 将所有节点存入优先队列,按照权值递增排序
PriorityQueue<TreeNode> queue = new PriorityQueue<>(w.length, (a, b) -> a.val - b.val);
for(int i=0; i<w.length; i++){
queue.offer(new TreeNode(w[i]));
}
// 构造哈夫曼树
while( queue.size() > 1 ){
// 弹出最小的两个节点
TreeNode node1 = queue.poll();
TreeNode node2 = queue.poll();
// 构造父节点
TreeNode father = new TreeNode(node1.val + node2.val);
father.left = node1;
father.right = node2;
// 父节点入队
queue.offer( father );
}
return queue.poll();
}