引言
哈夫曼树记住一点,有n
个需要编码的,那么节点就是2*n - 1
个,然后整个运算过程,在数据池找两个权重最小的作为左孩子和右孩子然后权重和生成一个父节点加入到数据池,作为左右孩子的节点就从数据池删除掉,直到最后池子里就一个点了,这时候就是所有的点都是独一无二的编码,然后权重最小(整体带权路径长度最小)
原理
哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的 路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)
计算公式
树的带权路径长度记为WPL=(W1L1+W2L2+W3L3+…+WnLn) ,N个权值Wi(i=1,2,…n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,…n)。 可以证明哈夫曼树的WPL是最小的
运算过程
一、对给定的n个权值{W1,W2,W3,…,Wi,…,Wn}构成n棵二叉树的初始集合F= {T1,T2,T3,…,Ti,…,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。(为方便在计算机上实现算 法,一般还要求以Ti的权值Wi的升序排列。)
二、在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。
三、从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。
四、重复二和三两步,直到集合F中只有一棵二叉树为止
使用的例子和最终形成的二叉树
生成的过程
先不写了,有点懒
代码
<!DOCTYPE html>
<html>
<head>
<title>哈夫曼树</title>
<meta charset="utf-8">
<script>
function Htreetype(){
this.name = "";
this.weight = 0;
this.Lchild = this.Rchild = null;
}
function newsort(x,y){
return x.weight - y.weight;
}
function PreOrderTravel(root){
if(root){
document.write(root.name + " "+ root.weight + " ");
PreOrderTravel(root.Lchild);
PreOrderTravel(root.Rchild);
}
}
function init(){
let hash = {
"Bob":100,"Lily":90,"test1":103,"test2":500,"test3":70,"test4":34,"test5":70};
let student = [];
document.write("学生信息</br>");
for(let index in hash){
document.write(index + " : " +hash[index] + "</br>");
let newstudent = new Htreetype();
newstudent.name = index;
newstudent.weight = hash[index];
student.push(newstudent);
}
//构造哈夫曼树然后哈夫曼编码
//每次都找两个最小权重的节点
while(student.length > 1){
student.sort(newsort);
let node = new Htreetype();
let temp1 = student.shift();
let temp2 = student.shift();
node.name = "node";
node.weight = temp1.weight + temp2.weight;
node.Lchild = temp1;
node.Rchild = temp2;
student.push(node);
}
document.write("</br>");
//然后遍历编码
//这里就展示下构造完成的二叉树
document.write("先序遍历二叉树</br>");
PreOrderTravel(student[0]);
document.write("</br>");
//这里是编码最终结果
//左是0.右是1
var result = [];
function PreOrderTravelCode(root,str){
if(root == null){
return;
}
if(root.Lchild == null&&root.Rchild == null){
result.push(root.name + " " + root.weight + " " + str);
}else{
PreOrderTravelCode(root.Lchild,str+"0");
PreOrderTravelCode(root.Rchild,str+"1");
}
}
PreOrderTravelCode(student[0],"");
document.write("编码结果</br>");
for(let i = 0; i < result.length; i++){
document.write(result[i]+"</br>");
}
}
</script>
</head>
<body onload="init()">
</body>
</html>