Huffman Coding Einführung
Huffman Coding befasst sich mit dem Codierungspaarungsproblem von Zeichen und binären Zeichen, das in Codierung und Dekodierung unterteilt ist, um die Binärdatenlänge zu komprimieren, die den Zeichen entsprechend entsprechend sind. Wir wissen, dass die Charaktere, wenn sie gespeichert und übertragen werden, binär sind (der Computer kennt nur 0/1), sodass es eine Zuordnungsbeziehung zwischen Zeichen und Binärer gibt. Charaktere gehören zum Zeichensatz (charset). Zeichen müssen durch Enkodus in binärer und übertragen werden. Wenn sie angezeigt werden, müssen sie zu Charakteren zurückgeschlüsselt werden. Die Charakter-Set- und Codierungsmethoden sind Eins-zu-viele-Beziehungen (Unicode kann mit UTF-8, UTF-16 usw. codiert werden). Nach dem Verständnis des Charakters, Codierens und Dekodierens kann das Problem des über den ganzen Himmels fliegenden Codes leicht gelöst werden. In der ASCII -Codierung ist die Dezimalzahlung der Kleinbuchstaben A des englischen Buchstabens 97 und die Binärdatei 01100001. Jedes Zeichen in ASCII ist mit 8 Bit (1Byte) codiert. Wenn 1000 Zeichen übertragen werden müssen, müssen 8000 Bit übertragen werden. Das Problem ist, dass die Häufigkeit der Verwendung des Buchstabens E in englischer Sprache 12,702%beträgt, während Z 0,074%beträgt. Ersteres ist mehr als 100 -mal so hoch wie das der letzteren, verwendet aber binär mit denselben Ziffern. Es kann besser gemacht werden, die Methode ist eine Codierung der variablen Länge. Das Leitprinzip besteht darin, die höhere Frequenz mit kürzeren Ziffern und solchen mit niedriger Frequenz mit längeren Ziffern zu codieren. Der Huffman -Codierungsalgorithmus befasst sich mit solchen Problemen.
Huffman codieren die Java -Implementierung
Die Datenstrukturen, die hauptsächlich vom Huffman -Codierungsalgorithmus verwendet werden, sind vollständige binäre Bäume und vorrangige Warteschlangen. Letzterer verwendet Java.util.PriorityQueue und die ersteren implementiert sich selbst (alle sind interne Klassen). Der Code ist wie folgt:
statischer Klassenbaum {private Knotenwurzel; public node getroot () {return root; } public void setRoot (Knoten root) {this.root = root; }} statischer Klassenknoten implementiert vergleichbar <node> {private String chars = ""; private int frequency = 0; Privatknoteneltern; private Knoten -Linkspitze; privater Knoten Rightnode; @Override public int vergleicheto (Knoten n) {Rückgabefrequenz - n.Frequence; } public boolean isleaf () {return chars.length () == 1; } public boolean isroot () {return parent == null; } public boolean isleftChild () {return parent! = null && this == parent.leftnode; } public int getfRequence () {Rückgabefrequenz; } public void setFrequence (int Frequenz) {this.Frequency = Frequenz; } public String getChars () {return chars; } public void setchars (String chars) {this.chars = chars; } public node getParent () {Return Parent; } public void setParent (Knoten übergeordnet) {this.Parent = Eltern; } public node getleftnode () {return Leftnode; } public void setLeftnode (Knoten links) {this.leftnode = linkNode; } public node getRightNode () {return rightnode; } public void setrightNode (Knoten rechten) {this.rightNode = rightnode; }} Statistiken
Da die Codierungstabelle gemäß der Frequenz angeordnet werden muss, müssen Sie natürlich die statistischen Informationen der Häufigkeit erhalten. Ich habe eine Methode implementiert, um ein solches Problem zu lösen. Wenn bereits Statistiken vorhanden sind, konvertieren Sie zu MAP <Zeichen, Ganzzahl>. Wenn die Informationen, die Sie erhalten, einen Prozentsatz sind, multiplizieren Sie mit 100 oder 1000 oder 10000. Sie können immer in eine Ganzzahl umgewandelt werden. Beispielsweise beträgt 12,702% multipliziert mit 1000 12702, und Huffman Codierung kümmert sich nur um Größenprobleme. Die statistische Methode wird wie folgt implementiert:
public static map <charakter, Integer> Statistik (char [] charArray) {map <charakter, Integer> map = new HashMap <Zeichen, Integer> (); für (charc c: charArray) {charakter charakter = neuer Zeichen (c); if (map.containsKey (Zeichen)) {map.put (Zeichen, map.get (Zeichen) + 1); } else {map.put (Zeichen, 1); }} return map; } Einen Baum bauen
Der Bau eines Baumes ist ein Kernschritt im Huffman -Codierungsalgorithmus. Die Idee ist, alle Zeichen an einem Blattknoten eines vollständig binären Baumes zu hängen, und die Frequenz des linken Knotens eines nicht-seitigen untergeordneten Knotens erscheint nicht mehr als der rechte Knoten. Der Algorithmus wandelt Statistiken in Knoten um und speichert sie in einer vorrangigen Warteschlange. Jedes Mal, wenn zwei Knoten mit der minimalen Frequenz aus der Warteschlange auftauchen, wird ein neuer übergeordneter Knoten (Nicht-Blattknoten) konstruiert. Die Summe der beiden Knoten, deren Charakterinhalt nur auftaucht, und die Frequenz ist auch ihre Summe. Das erste Popup wird als linker untergeordneter Knoten verwendet und der nächste als der rechte Kinderknoten verwendet, und der neu konstruierte übergeordnete Knoten wird in die Warteschlange platziert. Wiederholen Sie die obigen Aktionen n-1-Zeiten, n ist die Anzahl der verschiedenen Zeichen (die Anzahl in der Warteschlange wird jedes Mal um 1 reduziert). Beenden Sie die obigen Schritte, es gibt einen Knoten in der Warteschlange, und der Wurzelknoten des Baumes auftaucht auf. Der Code ist wie folgt:
private static tree buildtree (map <Zeichen, Integer> Statistik, Liste <node> Blätter) {Zeichen [] keys = Statistik.Keyset (). TOARRAY (neues Zeichen [0]); PriorityQueue <node> priorityQueue = new priorityQueue <node> (); für (Zeichenzeichen: Schlüssel) {Node node = new node (); node.chars = charakter.toString (); Node.Frequency = Statistics.get (Zeichen); priorityQueue.add (Knoten); Blätter.Add (Knoten); } int size = priorityQueue.size (); für (int i = 1; i <= size - 1; i ++) {node node1 = priorityQueue.poll (); Node node2 = priorityQueue.poll (); Node sumnode = new node (); sumnode.chars = node1.chars + node2.chars; Sumnode.Frequency = Node1.Fraquence + Node2.Fraquence; sumnode.leftnode = node1; sumnode.rightNode = node2; node1.parent = sumnode; node2.Parent = sumnode; priorityQueue.add (Sumnode); } Tree tree = new tree (); tree.root = priorityQueue.poll (); Return Tree; } Codierung
Die entsprechende Codierung eines Zeichens besteht darin, aus dem Blattknoten zu suchen, in dem sich das Zeichen befindet. Wenn der Zeichenknoten der linke Knoten des übergeordneten Knotens ist, fügen Sie 0 vor dem codierten Zeichen hinzu. Andernfalls fügen Sie 1 bis zum Stammknoten hinzu. Solange die Zuordnungsbeziehung zwischen Zeichen und Binärcode erhalten wird, ist die Codierung sehr einfach. Der Code ist wie folgt:
öffentliche statische String -Encode (String OriginalStr, Map <Zeichen, Integer> Statistik) {if (OriginalStr == null || OriginalStr.Equals ("")) {return ""; } char [] charArray = OriginalStr.toCharArray (); LIST <Knode> leafnodes = new ArrayList <node> (); BuildTree (Statistik, Leafnodes); Karte <Zeichen, String> codinfo = buildenCodingInfo (Leafnodes); StringBuffer Buffer = new StringBuffer (); für (char c: charArray) {charakter charakter = neuer Zeichen (c); buffer.Append (codinfo.get (Zeichen)); } return buffer.toString (); } private statische Karte <Zeichen, String> buildeCodingInfo (Liste <knode> leafnodes) {map <Zeichen, String> codeWords = new Hashmap <Zeichen, string> (); für (Knoten Leafnodes: Leafnodes) {Zeichen charakter = new Zeichen (leafnode.getchars (). charat (0)); String codeWord = ""; Node curralNode = leafnode; do {if (currentNode.isleftChild ()) {codeWord = "0" + codewort; } else {codeWord = "1" + codeWord; } currentNode = currentNode.parent; } while (currentNode.parent! = null); codeWords.put (Zeichen, Codewort); } Return Codewors; } Dekodierung
Da der Huffman -Codierungsalgorithmus sicherstellen kann, dass ein Binärcode nicht das Präfix eines anderen Code ist, ist die Dekodierung sehr einfach. Nehmen Sie jedes Bit der Binärdatei nach Abfolge heraus, suchen Sie von der Baumwurzel, 1 nach rechts, 0 nach links, erreichen Sie den Blattknoten (Hit) und kehren Sie zum Wurzelknoten zurück und wiederholen Sie die obigen Aktionen weiter. Der Code ist wie folgt:
public static String decode (String -Binarystr, Karte <Zeichen, Integer> Statistik) {if (binarystr == null || binarystr.equals ("")) {return ""; } char [] BinaryCharArray = Binarystr.toCharArray (); LinkedList <Scharakter> BinaryList = new LinkedList <Scharakter> (); int size = binarycharArray.length; für (int i = 0; i <size; i ++) {binaryList.addlast (neues Zeichen (BinarycharArray [i])); } List <node> leafnodes = new ArrayList <node> (); Baumbaum = Buildtree (Statistik, Leafnodes); StringBuffer Buffer = new StringBuffer (); while (binaryList.size ()> 0) {node node = tree.root; do {Zeichen c = BinaryList.removeFirst (); if (c.CharValue () == '0') {node = node.leftnode; } else {node = node.rightNode; }} while (! node.islaf ()); buffer.Append (node.chars); } return buffer.toString (); } Test und Vergleich
Die folgenden Tests zur Richtigkeit der Huffman -Codierung (zuerst codiert, dann dekodiert, einschließlich Chinesen) und Vergleich der Huffman -Codierung mit gemeinsamen Zeichenkodierung von Binärstrings. Der Code ist wie folgt:
public static void main (String [] args) {String oristr = "Huffman -Codes komprimieren Daten sehr effektiv: Einsparungen von 20% bis 90% sind typisch," + "Abhängig von den Eigenschaften der komprimierten Daten. Chinas Aufstieg"; Karte <Zeichen, Integer> Statistik = Statistik (Oristr.toCharArray ()); String codedBinaristr = codieren (oristr, Statistik); String decodedStr = decode (codedBinaristr, Statistik); System.out.println ("Original String:" + oristr); System.out.println ("Huffman -binärer String:" + codedBinaristr); System.out.println ("decodierte String von Binariy String:" + decodedStr); System.out.println ("binäre Zeichenfolge von UTF-8:" + GetStringOfByte (Oristr, charset.forname ("utf-8")); System.out.println ("binäre Zeichenfolge von UTF-16:" + getStringofByte (oristr, charset.forname ("utf-16")); System.out.println ("binäre Zeichenfolge von US-Ascii:" + GetStringOfByte (Oristr, charset.forname ("US-accii")); System.out.println ("binäre Zeichenfolge von GB2312:" + getStringofByte (Oristr, charset.forname ("gb2312")); } public static String getStringOfByte (String str, charSet charset) {if (str == null || str.equals ("")) {return ""; } byte [] bytearray = str.getBytes (charSet); int size = bytearray.length; StringBuffer Buffer = new StringBuffer (); für (int i = 0; i <size; i ++) {byte temp = bytearray [i]; buffer.Append (getStringofByte (temp)); } return buffer.toString (); } public static String getStringOfByte (Byte b) {StringBuffer buffer = new StringBuffer (); für (int i = 7; i> = 0; i--) {byte temp = (byte) ((b >> i) & 0x1); buffer.Append (string.Valueof (temp)); } return buffer.toString (); }Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.