Skip to content

Commit ce19ac9

Browse files
committed
java huffman
1 parent ad06db1 commit ce19ac9

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed

algorithms/Huffman.java

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
package algorithms;
2+
3+
import java.io.*;
4+
import java.util.*;
5+
6+
//очередь с приоритетами
7+
class PriorQueue<T extends Comparable> {
8+
//на основе обычного ссылочного массива
9+
ArrayList<T> arr = new ArrayList<T>();
10+
11+
//добавляем в конец = O(1)
12+
public void add(T obj) {
13+
arr.add(obj);
14+
}// add
15+
16+
//извлекаем наименьший элемент = O(N)
17+
public T get() {
18+
if (arr.size() == 0)
19+
return null;
20+
21+
//ищем наименьший элемент
22+
T prior = arr.get(0);
23+
for (int i = 1; i < arr.size(); i++) {
24+
if (arr.get(i).compareTo(prior) < 0) {
25+
prior = arr.get(i);
26+
}
27+
}
28+
//найденный элемент удаляем
29+
arr.remove(prior);
30+
31+
return prior;
32+
}// add
33+
34+
public int size() {
35+
return arr.size();
36+
}
37+
} // PriorQueue
38+
39+
public class Huffman {
40+
//вершина дерева - вверху (наименьший путь) популярные записи, внизу редкие
41+
Node root;
42+
43+
//таблицы соответствия = буква - битовая карта
44+
// [буква] = бинарный код
45+
String codeTable_in[] = new String[256];
46+
// [бинарный код] = буква
47+
HashMap<String, Character> codeTable_out = new HashMap<String, Character>();
48+
49+
public Huffman(Node r) {
50+
this.root = r;
51+
}
52+
53+
//ветвь дерева
54+
static class Node implements Comparable<Node> {
55+
//буква
56+
public Character ch;
57+
//частота символа
58+
public Integer freq;
59+
//ветви ниже
60+
public Node left;
61+
public Node right;
62+
63+
public Node(Character c, Integer f) {
64+
this.ch = c;
65+
this.freq = f;
66+
} // Node
67+
68+
public Node(Node l, Node r) {
69+
//частота родителя = сумме частоты детей
70+
this.freq = l.freq + r.freq;
71+
this.left = l;
72+
this.right = r;
73+
} // Node
74+
75+
@Override
76+
public int compareTo(Node h) {
77+
return this.freq - h.freq;
78+
} // compareTo
79+
80+
public void dump(Huffman parrent) {
81+
if (this.left != null)
82+
this.left.dump(parrent);
83+
if (this.ch != null) {
84+
String pout = this.ch + " (" + this.freq + ")";
85+
if (parrent != null) {
86+
pout = pout + " = " + parrent.codeTable_in[(char) this.ch];
87+
}
88+
System.out.println(pout);
89+
}
90+
if (this.right != null)
91+
this.right.dump(parrent);
92+
} // dump
93+
} // node
94+
95+
//частота символов в файле
96+
public static int[] getFreqFromFile(String file) throws IOException {
97+
int[] freq = new int[256];
98+
BufferedReader br = new BufferedReader(
99+
new FileReader(file));
100+
try {
101+
String line = br.readLine();
102+
while (line != null) {
103+
for (char c : line.toCharArray()) {
104+
//если это необходимые символы
105+
if (c > 0 && c < 256) {
106+
//увеличиваем счетчик кол-ва символов
107+
freq[c]++;
108+
}
109+
}
110+
line = br.readLine();
111+
}
112+
} finally {
113+
br.close();
114+
}
115+
return freq;
116+
} // getFreqFromFile
117+
118+
//создаем таблицу соответствия буква - сжатая битовая карта
119+
public void makeCodeTable() {
120+
//прямая карта
121+
makeCodeTableIn(this.root, "");
122+
//обратая карта
123+
for (int i = 0; i < this.codeTable_in.length; i++) {
124+
codeTable_out.put(this.codeTable_in[(char) i], (char) i);
125+
}
126+
} // makeCodeTableIn
127+
128+
protected void makeCodeTableIn(Node n, String code) {
129+
if (n == null)
130+
return;
131+
if (n.ch != null) {
132+
this.codeTable_in[(char) n.ch] = code;
133+
}
134+
//при переходе ниже левее увеличиваем битовую карту на 0 справа
135+
this.makeCodeTableIn(n.left, code + "0");
136+
//при перехода направо ниже увеличиваем битовую карту на 1 справа
137+
this.makeCodeTableIn(n.right, code + "1");
138+
} // makeCodeTableIn
139+
140+
//сжатие текста
141+
public String compress(String txt) {
142+
String result = new String();
143+
144+
//проходимся по каждому символу текста
145+
for (int i = 0; i < txt.length(); i++) {
146+
//если символ есть в таблице преобразования
147+
if (txt.charAt(i) < 256 && this.codeTable_in[txt.charAt(i)] != null) {
148+
result = result + this.codeTable_in[txt.charAt(i)];
149+
} else {
150+
//если нет, то просто вставляем символ
151+
result = result + txt.charAt(i);
152+
}
153+
}
154+
return result;
155+
} // compress
156+
157+
//разжатие текста
158+
public String decompress(String txt) {
159+
String result = new String();
160+
String buf = "";
161+
162+
//обходим каждый бит
163+
for (int i = 0; i < txt.length(); i++) {
164+
//накапливаем буфер битов
165+
buf = buf + txt.charAt(i);
166+
167+
//если буфер есть в таблице соответствия
168+
if (codeTable_out.containsKey(buf)) {
169+
//берем из таблицы и сбрасываем буфер
170+
result = result + codeTable_out.get(buf);
171+
buf = "";
172+
} else if (txt.charAt(i) >= 256 || this.codeTable_in[txt.charAt(i)] == null) {
173+
// нет в таблице преобразования - выдаем как есть
174+
result = result + txt.charAt(i);
175+
buf = "";
176+
}
177+
}
178+
result = result + buf;
179+
return result;
180+
} // compress
181+
182+
public void dump() {
183+
this.root.dump(this);
184+
} // dump
185+
186+
public static void main(String[] args) throws IOException {
187+
int[] freq = getFreqFromFile("C:\\Users\\007\\Google Диск\\info\\blog-02-17-2017.xml");
188+
PriorQueue<Node> pq = new PriorQueue();
189+
for (int i = 0; i < freq.length; i++) {
190+
if (freq[i] > 0) {
191+
pq.add(new Node((char) i, freq[i]));
192+
}
193+
}
194+
while (pq.size() > 1) {
195+
Node l = pq.get();
196+
Node r = pq.get();
197+
pq.add(new Node(l, r));
198+
}
199+
200+
Huffman h = new Huffman(pq.get());
201+
h.makeCodeTable();
202+
String test_string = "abcdeя f`d";
203+
String compr_string = h.compress(test_string);
204+
String decompr_string = h.decompress(compr_string);
205+
System.out.println(test_string);
206+
System.out.println(compr_string);
207+
System.out.println(decompr_string);
208+
// h.dump();
209+
} // main
210+
} // Huffman

0 commit comments

Comments
 (0)