前言:
Huffman树,即最小生成树。
其构造过程如下:
哈夫曼树并不唯一,但带权路径长度一定是相同的。
如下,有权值为1,5,8,4的四个结点,
其huffman树构造过程如下:
总的来说,可以归结为以下几个步骤:
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,哈夫曼树的构造规则为:
1. 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
2. 在森林中选出根结点的权值最小的两棵树进行合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
3. 从森林中删除选取的两棵树,并将新树加入森林;
4. 重复(02)、(03)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
话不多说,代码如下:
package Huffman树;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Huffman {
static class node implements Comparable<node>{//自排序
int weight;//权值
node lchild;
node rchild;
public node(int w,node l,node r)
{
this.weight=w;
this.lchild=l;
this.rchild=r;
}
public int compareTo(node o) {
return this.weight-o.weight;
}
}
static node createHuffmanTree(ArrayList<node> nodes)
{
while(nodes.size()>1)
{
Collections.sort(nodes);//排序
node l=nodes.get(0);
node r=nodes.get(1);
//System.out.println(l.weight+" "+r.weight);
node p=new node(l.weight+r.weight,l,r);
//移走两个最小的
nodes.remove(0);
nodes.remove(0);
//把大的放进去
nodes.add(p);
}
return nodes.get(0);
}
//前序遍历,并求WPL 带权路径长度
static long WPL=0;
static void preorder(node root,int levelNum)
{
if(root.lchild==null)
{
WPL+=root.weight*levelNum;
return;
}
else
{
preorder(root.lchild,levelNum+1);
preorder(root.rchild,levelNum+1);
}
}
public static void main(String[] args) {
ArrayList<node> nodes=new ArrayList<node>();
Scanner cin=new Scanner(System.in);
int n=cin.nextInt();
for(int i=0;i<n;i++)
{
int w=cin.nextInt();//这里我直接把它的权值当做name了
nodes.add(new node(w,null,null));
}
node r=createHuffmanTree(nodes);
WPL=0;//WPL:带权路径长度
preorder(r,0);
System.out.println("WPL: "+WPL);
cin.close();
}
}