コミック「ハフマンツリー」とは?

著者|小灰

ソース|プログラマXiaohui(ID:chengxuyuanxiaohui)

—————翌日—————

————————————

コンセプト1:パスとは?

ツリーでは、あるノードから別のノードに渡されるすべてのノードは、2つのノード間のパスと呼ばれます。

上記のバイナリツリーでは、ルートノードAからリーフノードHへのパスはA、B、D、Hです。

コンセプト2:パスの長さとは何ですか?

ツリーでは、あるノードから別のノードに移動する「エッジ」の数は、2つのノード間のパスの長さと呼ばれます。

バイナリツリーの例を今でも使用して、ルートノードAからリーフノードHまで、合計3つのエッジが渡されるため、パスの長さは3になります。

コンセプト3:ノードの重み付きパスの長さは?

ツリーの各ノードは独自の「重み」(重み)を持つことができ、重みは異なるアルゴリズムで異なる役割を果たすことができます。

ノードの重み付きパス長は、ツリーのルートノードからノードまでのパス長とノードの重みの積を指します。

ノードHの重みが3で、ルートノードからノードHまでのパス長も3であるとします。したがって、ノードHの重み付きパス長は3 X 3 = 9です。

コンセプト4:ツリーの重み付きパスの長さは?

ツリーでは、すべてのリーフノードの重み付けされたパスの長さの合計は、ツリーの重み付けされたパスの長さと呼ばれ、略してWPLとも呼ばれます。

このバイナリツリーを例にとると、ツリーのパス長は3X3 + 6X3 + 1X2 + 4X2 + 8X2 = 53です。

ハフマンツリーは、1952年にマサチューセッツ工科大学のハフマン博士によって発明されました。これはどのようなツリーですか?

ツリーの重み付きパスの長さ(WPL)を学習しました。ハフマンツリーは、リーフノードと重みが決定されている条件下で、重み付きパスの長さが最小のバイナリツリーです。 。

たとえば、それぞれ1、3、4、6、8の重みを持つリーフノードがある場合、重み付けされたパスの長さが最小になるようにするには、どのようなバイナリツリーを構築する必要がありますか?

原則として、重みが小さい葉ノードを根から離し、重みが大きい葉ノードを根に近づけます。

下の図の左側のツリーは、WPLが46のハフマンツリーで、前の例の53よりも小さくなっています。

同じリーフノードによって形成されるハフマンツリーが複数存在する場合があることに注意してください。次のツリーはすべてハフマンツリーです。

リーフノードが6つあり、重みが2、3、7、9、18、25の順になっているとします。ハフマンツリー、つまり重みパスの長さが最小のツリーを作成するにはどうすればよいでしょうか。

ステップ1:フォレストを構築する

各リーフノードを独立したツリー(ルートノードのみを持つツリー)として扱い、フォレストを形成します。

上の図では、リーフノードのフォレストが右側、補助キューが左側にあり、すべてのリーフノードは重みの降順で格納されています。補助キューの役割については、後で説明します。

ステップ2:現在の重みが最小の2つのノードを選択して、新しい親ノードを生成する

補助キューを使用して、重みが最小のノード2と3を見つけ、これら2つのノードに基づいて新しい親ノードを生成できます。親ノードの重みは、これら2つのノードの重みの合計です。

手順3:前の手順で選択した2つの最小ノードをキューから削除し、新しい親ノードをキューに追加する

つまり、キューから2と3を削除し、5を挿入して、キューの昇順を維持します。

ステップ4:現在の重みが最小の2つのノードを選択して、新しい親ノードを生成します。

これは、2番目のステップで繰り返される操作です。現在のキューで最小の重みを持つノードは5と7であり、新しい親ノードを生成するための重みは5 + 7 = 12です。

手順5:前の手順で選択した2つの最小ノードをキューから削除し、新しい親ノードをキューに追加します。

これは、キューから5と7を削除し、12を挿入し、さらにキューの昇順を維持する、3番目のステップの繰り返し操作です。

ステップ6:現在の重みが最小の2つのノードを選択して、新しい親ノードを生成します。

これは、2番目のステップで繰り返される操作です。現在のキューで最小の重みを持つノードは9と12で、新しい親ノードの重みは9 + 12 = 21です。

手順7:前の手順で選択した2つの最小ノードをキューから削除し、新しい親ノードをキューに追加します。

これは、キューから9と12を削除し、21を挿入し、さらにキューの昇順を維持する、3番目のステップの繰り返し操作です。

ステップ8:現在の重みが最小の2つのノードを選択して、新しい親ノードを生成します。

これは、2番目のステップで繰り返される操作です。現在のキューで最小の重みを持つノードは18と21で、新しい親ノードの重みは18 + 21 = 39です。

手順9:前の手順で選択した2つの最小ノードをキューから削除し、新しい親ノードをキューに追加します。

これは、キューから18と21を削除し、39を挿入して、キューの昇順を維持するという3番目のステップの繰り返し操作です。

ステップ10:現在の重みが最小の2つのノードを選択して、新しい親ノードを生成します。

これは、2番目のステップで繰り返される操作です。現在のキューで最小の重みを持つノードは25と39であり、新しい親ノードを生成するための重みは25 + 39 = 64です。

手順11:前の手順で選択した2つの最小ノードをキューから削除し、新しい親ノードをキューに追加する

これは、キューから25と39を削除して64を挿入する、3番目のステップの繰り返し操作です。

現時点では、キューにはノードが1つしかありません。これは、フォレスト全体がツリーにマージされたことを示しており、このツリーが必要なハフマンツリーです。

private Node root;
private Node[] nodes;

//构建哈夫曼树
public void createHuffman(int[] weights) {

//优先队列,用于辅助构建哈夫曼树

Queue<Node> nodeQueue = new PriorityQueue<>();
    nodes = new Node[weights.length];


//构建森林,初始化nodes数组

for(int i=0; i<weights.length; i++){
        nodes[i] = new Node(weights[i]);
        nodeQueue.add(nodes[i]);

}


//主循环,当结点队列只剩一个结点时结束

while (nodeQueue.size() > 1) {

//从结点队列选择权值最小的两个结点

Node left = nodeQueue.poll();

Node right = nodeQueue.poll();

//创建新结点作为两结点的父节点

Node parent = new Node(left.weight + right.weight, left, right);
        nodeQueue.add(parent);

}
    root = nodeQueue.poll();
}

//按照前序遍历输出
public void output(Node head) {

if(head == null){

return;

}

System.out.println(head.weight);
    output(head.lChild);
    output(head.rChild);
}

public static class Node implements Comparable<Node>{

int weight;

Node lChild;

Node rChild;


public Node(int weight) {

this.weight = weight;

}


public Node(int weight, Node lChild, Node rChild) {

this.weight = weight;

this.lChild = lChild;

this.rChild = rChild;

}


@Override

public int compareTo(Node o) {

return new Integer(this.weight).compareTo(new Integer(o.weight));

}
}

public static void main(String[] args) {

int[] weights = {2,3,7,9,18,25};

HuffmanTree huffmanTree = new HuffmanTree();
    huffmanTree.createHuffman(weights);
    huffmanTree.output(huffmanTree.root);
}

このコードでは、ノードキュー内のノードが常に重みの昇順で配置されるようにするために、優先度キューPriorityQueueを使用します。

同時に、静的内部クラスNodeは、比較インターフェースを実装し、compareToメソッドを書き換えて、Nodeオブジェクトがキューに入るときに重みに従って確実に比較されるようにする必要があります。


【終わり】

よりエキサイティングな推奨事項

ネットを介して周がブロックした360人の大物:草の根の労働者が36歳の何億もの反撃に!

2020年、サイバーセキュリティで学ぶ価値のある5つのプログラミング言語

☞10x HDは無料です!大麦エンドセレクションSVGレンダリング

☞マイクロソフトは一人のために会社を買収しましたか?ソニーのプログラムを解読し、ハッカーの小説を書き、彼の厳しいプログラムの人生を見てください!

機械学習プロジェクトテンプレート:MLプロジェクトの6つの基本ステップ

☞IBM、Microsoft、Apple、Google、Samsung ...ブロックチェーンにあるこれらの巨大テクノロジーはすでに多くのことを行っています!

上級プログラマーによるまとめ:Linuxプロセスを分析する6つの方法をすべてお話しします

今日の福祉:コメント欄にコメントを残すと、299元相当の「2020 AI開発者1万会議」の生放送のチケットを入手できます指を動かして、言いたいことを書いてください。

クリックして元のテキストを読んでください。すばらしいです。

あなたが注文するすべての「ウォッチング」、私はそれを真剣に受け止めます

リリース1940元の記事 ウォンの賞賛40000 + ビュー1813万+

おすすめ

転載: blog.csdn.net/csdnnews/article/details/105424420