给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。要构成哈夫曼树,值比较大的叶子节点高度越低越好。
(1) 将n个权值看出n颗只有根节点的树,构建n颗树。
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
(3)从森林中删除选取的两棵树,并将新树加入森林;
(4)重复(2)、(3)步n-1遍,最后森林中只有一棵树,这棵树就是哈夫曼树。
(5)直接用递归求它的带权路径长度即可。
java参考代码:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int n = sc.nextInt();
List<Tree> ts=new ArrayList<Tree>();
//构建n颗只有根节点的树
for(int i=0;i<n;i++)
ts.add(new Tree(sc.nextInt()));
//进行n-1次,删除最小的两棵树,合并两棵树并加进去
for(int i=0;i<n-1;i++)
removeAndAdd(ts);
//求带权路径长度
int ans=getNum(ts.get(0),0);
System.out.println(ans);
}
private static int getNum(Tree tree,int n)
{
if(tree.left==null&&tree.right==null)
return tree.data*n;
return getNum(tree.left, n+1)+getNum(tree.right, n+1);
}
private static void removeAndAdd(List<Tree> ts)
{
int min1=Integer.MAX_VALUE;
int min2=Integer.MAX_VALUE;
int inx1=-1;
int inx2=-1;
//找出两个最小值
for(int i=0;i<ts.size();i++)
{
Tree t=ts.get(i);
if(t.data<min1)
{
min1=t.data;
inx1=i;
}
else if(t.data<min2)
{
min2=t.data;
inx2=i;
}
}
//删除两颗最小的数,合并两棵树,并加入
Tree t1=ts.get(inx1);
Tree t2=ts.get(inx2);
Tree t=new Tree(t1.data+t2.data);
t.left=t1;
t.right=t2;
ts.remove(t1);
ts.remove(t2);
ts.add(t);
}
}
class Tree
{
int data;
Tree left;
Tree right;
Tree(int data) {
super();
this.data = data;
}
}