ハフマンツリーとその実現

まず、ハフマン木が何であるかを見て:

与えられたn個の重みのnとしてリーフノードツリーの加重経路の長さが最小に達した場合、二分木構造、例えば二分木もハフマン木(ハフマンツリー)として知られている最適なバイナリツリーと呼ばれます。ハフマンツリーは、最短経路長加重ツリーは、ルートノードから近い即ち大きな重みです。

また、最適なバイナリツリーとして知られているハフマンツリーは、最短の長さの正しいパスである二分木いわゆる木の重み付き経路長リーフノードに層0のルートノード、ルートノードがリーフ経路長である場合、ツリーは、経路長のすべてのリーフノードの重みは、(ルートノードする値が乗算され層)の点を接合を形成します。= WPLを付し、各ノードと長さのツリーのルートからのパスの経路長である(W1 * L1 + W2が * L2 + W3 * L3 + ... + Wnを* LN)、N 番目の重みのWi(私は、1,2 = ... N)Nのバイナリ構成はリーフノードを有しているから、対応するリーフノードの経路長は、Li(iは1,2 =、... Nです )。WPLは、ハフマン木が最小であることを証明することができます。

ハフマン木について、以下の存在は、いくつかの基本的な概念:

図1に示すように、パスとパスの長さ

ツリーで、子からのノード間のパスはパスと呼ばれる孫ノード、またはダウン達することができます。枝の数は、パス経路長と呼ばれています。層の所定の数がルートノードである場合、ルートノードから最初のノード層Lへのパスの長さはL-1です。

2、右ノードと加重経路長

ツリーノードが値を割り当てられた特定の意味を持っている場合、この値は右ノードと呼ばれています。ノードの加重経路長:ノードのノードとの間の右へのルートから経路長の積。

3、パスの長さ加重ツリー

加重路長を加重経路長と、すべてのリーフノードのツリーとして定義され、] WPLを付し、バイナリツリーの最適な形態は、最小WPL一意ではありません。

ハフマンツリー構造

 1)所与のn-重み{W1、W2、W3、W4 ...... WN}森F = {T1、T2、T3 ..... Tnを}、それぞれに応じてn個のバイナリツリーを構成しますWiの重量のバイナリツリーのみルートノード、左及び右サブツリーは空です。

  2)森Fを選択し、最小重み2つのルートノードバイナリツリーのを、新しいサブツリーが左として二分木右ので、二分木のルート・ノードであることをその新たな重みと左右のサブツリー。

  3)その2つのFから選択されたサブツリーを削除し、及びFから成る新しいバイナリは、フォレストに追加されます。

  森林は、得られる木がバイナリハフマン木である時にのみ、バイナリツリーを含むまで4)2、3の操作を繰り返します。
                                

 

ハフマン木は、Java実装の下に与えられています。(いくつかの変更が元に比べてあります)

package gxu.wjb.tree;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

/**
 * 哈夫曼树的构建
 * @version 创建时间:2019-8-9 下午2:51:02
 * 
 * 
 */
public class HuffmanTree {
	public static class Node<E> {
		E data;
		double weight;
		Node<E> leftChild;
		Node<E> rightChild;

		public Node(E data, double weight) {
			this.data = data;
			this.weight = weight;
		}
	}

	public static void main(String[] args) {
		List<Node<String>> nodes = new ArrayList<Node<String>>();
		nodes.add(new Node<String>("A", 40.0));
		nodes.add(new Node<String>("B", 8.0));
		nodes.add(new Node<String>("C", 10.0));
		nodes.add(new Node<String>("D", 30.0));
		nodes.add(new Node<String>("E", 10.0));
		nodes.add(new Node<String>("F", 2.0));

		Node<String> root = HuffmanTree.createTree(nodes);
		breadthFirst(root);
	}

	public static Node<String> createTree(List<Node<String>> nodes) {
		// 只要nodes列表中还有2个及以上的节点
		while (nodes.size() > 1) {
			quickSort(nodes, 0, nodes.size() - 1);
			// 获取权值最小的两个点
			Node<String> left = nodes.get(0);
			Node<String> right = nodes.get(1);
			// 生成新节点,新节点的权值为两个子节点权值之和
			Node<String> parent = new Node<String>(null, left.weight
					+ right.weight);
			// 让新节点作为两个最小节点的父节点
			parent.leftChild = left;
			parent.rightChild = right;

			// 删除两个最小节点
			nodes.remove(0);
			nodes.remove(0);

			// 将新节点加入到集合中
			nodes.add(parent);
		}

		// 剩余一个节点的时候返回即可
		return nodes.get(0);
	}

	/**
	 * 实现快速排序算法,该快排是基于荷兰国旗的思想进行改进后的实现,用于对节点进行排序
	 */
	public static void quickSort(List<Node<String>> nodes, int L, int R) {
		if (L < R) {
			int[] p = getProcess(nodes, nodes.get(L), L, R);
			quickSort(nodes, L, p[0] - 1);
			quickSort(nodes, p[1], R);
		}
	}

	private static int[] getProcess(List<Node<String>> nodes,
			Node<String> base, int L, int R) {
		int less = L - 1;
		int more = R + 1;
		int cur = L;
		while (cur < more) {
			if (nodes.get(cur).weight < base.weight) {
				swap(nodes, ++less, cur++);
			} else if (nodes.get(cur).weight == base.weight) {
				cur++;
			} else {
				swap(nodes, --more, cur++);
			}
		}

		return new int[] { less + 1, more };
	}

	/**
	 * 将指定集合中的i和j索引处的元素交换
	 * 
	 * @param nodes
	 * @param i
	 * @param j
	 * @return
	 */
	private static void swap(List<Node<String>> nodes, int i, int j) {
		Node<String> temp = nodes.get(i);
		nodes.set(i, nodes.get(j));
		nodes.set(j, temp);
	}

	// 广度优先遍历,也就是按层次遍历
	public static void breadthFirst(Node<String> head) {
		if (head == null) {
			return;
		}
		Queue<Node<String>> queue = new LinkedList<Node<String>>();
		queue.offer(head);
		while (!queue.isEmpty()) {
			head = queue.poll();
			System.out.println(head.data);
			if (head.leftChild != null) {
				queue.offer(head.leftChild);
			}
			if (head.rightChild != null) {
				queue.offer(head.rightChild);
			}
		}
	}
}

ハフマン符号化

ハフマン木によると、問題のメッセージコーディングを解決することができます。こうした「abcdabcaba」をコードする、ユニークなバイナリコードに変換して、あなたは文字列をしたいと仮定しますが、バイナリコード変換うちの最小の長さが必要です。

コードの長さWの周波数は、Lであると仮定し、nは、文字符号化、符号化されたバイナリコードの全長は、文字列が表示され、各文字の原理ハフマンツリーを発生しW1L1 + W2L2 + ... + WnLn、あります。したがってハフマン符号化ツリー構造原理バイナリので最短メッセージの長こと、使用することができます。

「abcdabcaba」の合計、B、C、D4文字、それぞれ出現4,3,2,1の数、その重量、A、B、Cに対応するために、dが出現構成の数に重みでありますハフマン木、得られた結果の左下。

あなたはリーフノードに到達するまで、左部分木コードに割り当てられたハフマンは、「0」、右部分木の上に「1」が割り当てられているルートノードから開始します。ハフマンそして、ツリーのルートからリーフノードコードは、各パスに沿って並ぶ、各リーフノードは右下に、コード取得する達します。
 

                              0画像

それぞれ、B、C、D 0,10,110,111コーディング対応する、図から分かるように、対応するバイナリコードに文字列「abcdabcaba」は、わずか19の長さ0101101110101100100です。これはまた、ハフマン符号化として知られている最短バイナリコードです。

公開された61元の記事 ウォンの賞賛9 ビュー30000 +

おすすめ

転載: blog.csdn.net/qq_33204444/article/details/98854199