ハフマンツリー
基本的な紹介
n個のリーフノードとしてn個の重みが与えられると、バイナリツリーが構築されます。ツリーの重み付きパス長(wpl)が最小に達すると、バイナリツリーは最適なバイナリツリーと呼ばれ、ハフマンツリー(ハフマンツリー)とも呼ばれます。 )、およびいくつかの本はホフマンツリーとして翻訳されています。
換言すれば、ハフマンツリーは、最短加重経路長の木である、およびより大きな持つノード重みは、ルートに近いです
いくつかの概念
パスとパスの長さ:ツリーでは、ノードから下に到達できる子ノードまたは孫ノード間のパスはパスと呼ばれます。パス内の分岐の数は、パス長と呼ばれます。ルートノードの層数を1と指定した場合、ルートノードからL番目の層のノードまでのパスの長さはL-1です。
ノードの重みと重み付きパスの長さ:ツリー内のノードに特定の意味を持つ値が割り当てられている場合、この値はノードの重みと呼ばれます。ノードの加重パス長は、ルートノードからノードまでのパスの長さとノードの重みの積です。
例えば:
ノードのパワー:13 14 5 16
例として、ノードの加重パス長は13です。彼のパスは、第1層から第3層まで2であるため、13 * 2 = 26になります。
ツリーの加重パス長:ツリーの加重パス長は、すべてのリーフノードの加重パス長の合計として定義され、WPL(加重パス長)として示されます。加重が大きいノードは、ルートノード二分木は最適な二分木です。
ハフマンツリー作成のアイデア
シーケンス{13,7,8,3,29,6,1}があるとすると、ハフマンツリーに変換する必要があります。
ステップ:
1.小さいものから大きいものへと並べ替え、各データをノードとして扱います。各ノードは最も単純な二分木と見なすことができます。
2.ルートノードの重みが最小の2つの二分木を取り出します
3に新たなバイナリツリーを形成する、のルートノードの重量新しいバイナリツリーは、前2つのバイナリツリーのルートノードの重みの合計であります
4.次に、Fengyunの新しいバイナリ(ルートノードの値を並べ替えの適切なサイズに変更)を、列数とすべてのデータが処理されるまで手順1-2-3-4を繰り返して、ハフマンツリーを取得します。
ステップ:
-
並べ替え1、3、4、7、8、13、29
-
1と3を選択して、新しいバイナリツリーを構築します
6番と組み合わせる
7,8は10より小さいので、別々に取り出して新しい二分木を形成します。
コード
package 赫夫曼树;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class HuffmanTree {
public static void main(String[] args) {
// TODO Auto-generated method stub
int arr[] = {
13,7,8,3,29,6,1};
Node node = createHuffmanTree(arr);
preOrder(node);
}
//创建赫夫曼树的方法
public static Node createHuffmanTree(int[] arr) {
//先把数组中的所有元素取出来,构建成Node类型
//放入到ArrayList中,可以排序
List<Node> nodes = new ArrayList<Node>();
for(int value : arr){
nodes.add(new Node(value));
}
while(nodes.size() > 1){
//排序 我们是从小到大
Collections.sort(nodes);
System.out.println(nodes);
//取根节点权值最小的两颗二叉树
//取出最小的二叉树节点(二叉树)
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
//构建新的二叉树
Node parent = new Node(leftNode.value+rightNode.value);
parent.left = leftNode;
parent.right = rightNode;
//从我们的ArrayList删除处理过的二叉树
nodes.remove(leftNode);
nodes.remove(rightNode);
//将parent加入到nodes集合中
nodes.add(parent);
System.out.println("第一次处理后"+nodes);
}
//返回赫夫曼树的root节点
return nodes.get(0);
}
//前序便利方法
public static void preOrder(Node root) {
if(root != null){
root.preOrder();
}else
{
System.out.println("空树");
}
}
}
//创建节点类
//为了让Node支持排序 Collections集合排序
//让Node实现Comparable接口
class Node implements Comparable<Node>{
int value;//节点权值
Node left;//指向左子节点
Node right;//指向右子节点
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node [value=" + value + "]";
}
@Override
public int compareTo(Node o) {
// TODO Auto-generated method stub
return this.value - o.value;//表示从小到大排序
}
//前序遍历的方法
public void preOrder() {
System.out.println(this);
if(this.left != null){
this.left.preOrder();
}
if(this.right != null){
this.right.preOrder();
}
}
}
の結果
[Node [value=1], Node [value=3], Node [value=6], Node [value=7], Node [value=8], Node [value=13], Node [value=29]]
第一次处理后[Node [value=6], Node [value=7], Node [value=8], Node [value=13], Node [value=29], Node [value=4]]
[Node [value=4], Node [value=6], Node [value=7], Node [value=8], Node [value=13], Node [value=29]]
第一次处理后[Node [value=7], Node [value=8], Node [value=13], Node [value=29], Node [value=10]]
[Node [value=7], Node [value=8], Node [value=10], Node [value=13], Node [value=29]]
第一次处理后[Node [value=10], Node [value=13], Node [value=29], Node [value=15]]
[Node [value=10], Node [value=13], Node [value=15], Node [value=29]]
第一次处理后[Node [value=15], Node [value=29], Node [value=23]]
[Node [value=15], Node [value=23], Node [value=29]]
第一次处理后[Node [value=29], Node [value=38]]
[Node [value=29], Node [value=38]]
第一次处理后[Node [value=67]]
Node [value=67]
Node [value=29]
Node [value=38]
Node [value=15]
Node [value=7]
Node [value=8]
Node [value=23]
Node [value=10]
Node [value=4]
Node [value=1]
Node [value=3]
Node [value=6]
Node [value=13]