[TOC]
基础概念
路径:
- 在一棵树中,从一个结点到另一个结点所经过的所有结点,被我们称为两个结点之间的路径
路径长度:
- 在一棵树中,从一个结点到另一个结点所经过的“边”的数量,被我们称为两个结点之间的路径长度。
结点的带权路径长度:
- 结点的带权路径长度,是指树的根结点到该结点的路径长度,和该结点权重的乘积。边数*权重
树的带权路径长度:
- 在一棵树中,所有叶子结点的带权路径长度之和,被称为树的带权路径长度,也被简称为WPL。
哈夫曼树
- 就是保重树的带权路径长度最小。
- 哈夫曼树不唯一。
- 复杂度:nlog(n) 队列:log(n) 节点:n
实现逻辑
- 借助辅助队列,由小到大入队列。
- 借助辅助队列,我们可以找到权值最小的结点2和3,并根据这两个结点生成一个新的父结点,父节点的权值是这两个结点权值之和。
- 从队列中移除上一步选择的两个最小结点,把新的父节点加入队列也就是从队列中删除2和3,插入5,并且仍然保持队列的升序。队列数据长度为一,结束。
图解
代码实现
package com.neusoft.data.structure;
//然后:实现哈夫曼树的主题类,其中包括两个静态的泛型方法,为创建哈夫曼树和广度优先遍历哈夫曼树
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
public class HuffmanTree<T> {
public static <T> Node<T> createTree(List<Node<T>> nodes){
//只要nodes数组中还有两个以上的节点
while(nodes.size() > 1){
Collections.sort(nodes);//1先排序数据
// 获取权值最小的两个节点
Node<T> left = nodes.get(nodes.size()-1); //倒数第一个
Node<T> right = nodes.get(nodes.size()-2);//倒数第二个
//生成新节点,新节点的权值为两个子节点的权值之和
Node<T> parent = new Node<T>(null, left.getWeight()+right.getWeight());
//让新节点作为权值最小的两个节点的父节点
parent.setLeft(left);
parent.setRight(right);
//删除权值最小的两个节点
nodes.remove(left);
nodes.remove(right);
//将新生成的节点添加到集合中
nodes.add(parent);
}
return nodes.get(0);
}
/*7 5 4 2
*
* 18
* 11 7
* 6 5
* 2 4
*
*
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
List<Node<String>> list = new ArrayList<Node<String>>();
list.add(new Node<String>("a",7));
list.add(new Node<String>("b",5));
list.add(new Node<String>("c",4));
list.add(new Node<String>("d",2));
Node<String> root = HuffmanTree.createTree(list);
System.out.println(HuffmanTree.breadth(root));
// System.out.println(list);
}
//广度优先遍历
public static <T> List<Node<T>> breadth(Node<T> root){
List<Node<T>> list = new ArrayList<Node<T>>();
Queue<Node<T>> queue = new ArrayDeque<Node<T>>();
if(root != null){
//将跟元素入"队列"
queue.offer(root);
}
while(!queue.isEmpty()){
//将该队列的"队尾"的元素添加到list中
list.add(queue.peek());
Node<T> node = queue.poll();
//如果左节点不为null,将它们加入队列
if(node.getLeft() != null){
queue.offer(node.getLeft());
}
//如果有节点不为null,将它们加入队列。
if(node.getRight() != null){
queue.offer(node.getRight());
}
}
return list;
}
}
class Node<T> implements Comparable<Node<T>> {
private T data;
private double weight; //权重
private Node<T> left;
private Node<T> right;
public Node(T data, double weight){
this.data = data;
this.weight = weight;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public Node<T> getLeft() {
return left;
}
public void setLeft(Node<T> left) {
this.left = left;
}
public Node<T> getRight() {
return right;
}
public void setRight(Node<T> right) {
this.right = right;
}
@Override
public String toString(){
return "data:"+this.data+";weight:"+this.weight;
}
@Override
public int compareTo(Node<T> other) {
if(other.getWeight() > this.getWeight()){
return 1;
}
if(other.getWeight() < this.getWeight()){
return -1;
}
return 0;
}
}
输出
[data:null;weight:18.0, data:a;weight:7.0, data:null;weight:11.0, data:b;weight:5.0, data:null;weight:6.0, data:d;weight:2.0, data:c;weight:4.0]