-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathHuffmanCode.java
125 lines (111 loc) · 3.37 KB
/
HuffmanCode.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/**
* Copyright 2022 jingedawang
*/
package greedy;
import utils.ArrayPrinter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.PriorityQueue;
/**
* Huffman code.
*
* Given the frequencies of each character, we need to find the most efficient encoding strategy to make the encoded
* text short. The variant encoding method is called Huffman code.
*/
public class HuffmanCode {
/**
* Demo code.
*/
public static void main(String[] args) {
char[] characters = {'a', 'b', 'c', 'd', 'e', 'f'};
int[] frequencies = {45, 13, 12, 16, 9, 5};
System.out.println("The character collection is:");
ArrayPrinter.print(characters);
System.out.println("The frequencies of each character are:");
ArrayPrinter.print(frequencies);
HuffmanCode huffmanCode = new HuffmanCode();
huffmanCode.buildHuffmanTree(characters, frequencies);
System.out.println();
System.out.println("The huffman code book is");
for (int i = 0; i < characters.length; i++) {
System.out.println(characters[i] + ": " + huffmanCode.encode(String.valueOf(characters[i])));
}
String str = "abcdef";
String code = huffmanCode.encode(str);
System.out.println("The huffman code of string \"" + str + "\" is " + code + ".");
}
/**
* Build the huffman tree using given characters and its corresponding frequencies.
*
* @param characters A character array.
* @param frequencies A frequency array corresponding to the character array.
*/
public void buildHuffmanTree(char[] characters, int[] frequencies) {
ArrayList<Node> list = new ArrayList<>(characters.length);
for (int i = 0; i < characters.length; i++) {
list.add(new Node(characters[i], frequencies[i]));
}
PriorityQueue<Node> queue = new PriorityQueue<>(list);
for (int i = 0; i < characters.length - 1; i++) {
Node left = queue.poll();
Node right = queue.poll();
Node root = new Node(' ', left.frequency + right.frequency);
root.left = left;
root.right = right;
queue.add(root);
}
Node huffmanTree = queue.poll();
codeBook = new HashMap<Character, String>(characters.length * 2);
generateCodeBook(huffmanTree, "");
}
/**
* Get the huffman encode of the given string.
*
* @param str The string to be encoded.
* @return The code of the string.
*/
public String encode(String str) {
StringBuilder stringBuilder = new StringBuilder();
for (char c : str.toCharArray()) {
stringBuilder.append(codeBook.get(c));
}
return stringBuilder.toString();
}
/**
* Inner Node class.
* <p>
* The comparison between instances is based on {@code frequency} field.
*/
private static class Node implements Comparable<Node> {
Node(char character, int frequency) {
this.character = character;
this.frequency = frequency;
}
char character;
int frequency;
Node left;
Node right;
@Override
public int compareTo(Node node) {
return this.frequency - node.frequency;
}
}
/**
* The code book field.
*/
private HashMap<Character, String> codeBook;
/**
* Generate the code book recursively.
*
* @param root The root of current subtree.
* @param prefix The prefix string from the root to this subtree.
*/
private void generateCodeBook(Node root, String prefix) {
if (root.left == null || root.right == null) {
codeBook.put(root.character, prefix);
} else {
generateCodeBook(root.left, prefix + "0");
generateCodeBook(root.right, prefix + "1");
}
}
}