Skip to content
Snippets Groups Projects
Commit e4292e00 authored by Vojtech Moravec's avatar Vojtech Moravec
Browse files

Report Huffman symbol frequencies in verbose mode on decompression.

parent 3804d8d7
No related branches found
No related tags found
No related merge requests found
...@@ -6,6 +6,8 @@ import azgracompress.huffman.Huffman; ...@@ -6,6 +6,8 @@ import azgracompress.huffman.Huffman;
import azgracompress.io.OutBitStream; import azgracompress.io.OutBitStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.util.Iterator;
import java.util.Map;
public abstract class CompressorDecompressorBase { public abstract class CompressorDecompressorBase {
public static final int LONG_BYTES = 8; public static final int LONG_BYTES = 8;
...@@ -30,6 +32,20 @@ public abstract class CompressorDecompressorBase { ...@@ -30,6 +32,20 @@ public abstract class CompressorDecompressorBase {
protected Huffman createHuffmanCoder(final int[] symbols, final long[] frequencies) { protected Huffman createHuffmanCoder(final int[] symbols, final long[] frequencies) {
Huffman huffman = new Huffman(symbols, frequencies); Huffman huffman = new Huffman(symbols, frequencies);
huffman.buildHuffmanTree(); huffman.buildHuffmanTree();
if (options.isVerbose()) {
StringBuilder sb = new StringBuilder();
sb.append("Huffman symbols and their probabilities:\n");
Iterator<Map.Entry<Integer, Double>> it = huffman.getSymbolProbabilityMap().entrySet().iterator();
while (it.hasNext()) {
final Map.Entry<Integer, Double> pair = (Map.Entry<Integer, Double>) it.next();
sb.append(String.format("%d: %.10f\n", pair.getKey(), pair.getValue()));
}
System.out.println(sb.toString());
}
return huffman; return huffman;
} }
......
package azgracompress.huffman; package azgracompress.huffman;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.PriorityQueue;
public class Huffman { public class Huffman {
HuffmanNode root = null; private HuffmanNode root = null;
HashMap<Integer, boolean[]> symbolCodes; private HashMap<Integer, boolean[]> symbolCodes;
final int[] symbols; private HashMap<Integer, Double> symbolProbabilityMap;
final long[] symbolFrequencies; private final int[] symbols;
private final long[] symbolFrequencies;
public Huffman(int[] symbols, long[] symbolFrequencies) { public Huffman(int[] symbols, long[] symbolFrequencies) {
assert (symbols.length == symbolFrequencies.length) : "Array lengths mismatch"; assert (symbols.length == symbolFrequencies.length) : "Array lengths mismatch";
...@@ -29,8 +28,6 @@ public class Huffman { ...@@ -29,8 +28,6 @@ public class Huffman {
parentB.getProbability())); parentB.getProbability()));
assert (parentA.getProbability() <= parentB.getProbability()); assert (parentA.getProbability() <= parentB.getProbability());
} }
assert (parentA != null && parentB != null);
parentA.setBit(1); parentA.setBit(1);
parentB.setBit(0); parentB.setBit(0);
...@@ -81,6 +78,7 @@ public class Huffman { ...@@ -81,6 +78,7 @@ public class Huffman {
} }
private PriorityQueue<HuffmanNode> buildPriorityQueue() { private PriorityQueue<HuffmanNode> buildPriorityQueue() {
symbolProbabilityMap = new HashMap<>(symbols.length);
double totalFrequency = 0.0; double totalFrequency = 0.0;
for (final long symbolFrequency : symbolFrequencies) { for (final long symbolFrequency : symbolFrequencies) {
totalFrequency += symbolFrequency; totalFrequency += symbolFrequency;
...@@ -90,6 +88,7 @@ public class Huffman { ...@@ -90,6 +88,7 @@ public class Huffman {
for (int sIndex = 0; sIndex < symbols.length; sIndex++) { for (int sIndex = 0; sIndex < symbols.length; sIndex++) {
final double symbolProbability = (double) symbolFrequencies[sIndex] / totalFrequency; final double symbolProbability = (double) symbolFrequencies[sIndex] / totalFrequency;
symbolProbabilityMap.put(symbols[sIndex], symbolProbability);
queue.add(new HuffmanNode(symbols[sIndex], symbolProbability, symbolFrequencies[sIndex])); queue.add(new HuffmanNode(symbols[sIndex], symbolProbability, symbolFrequencies[sIndex]));
} }
...@@ -104,4 +103,25 @@ public class Huffman { ...@@ -104,4 +103,25 @@ public class Huffman {
public HuffmanNode getRoot() { public HuffmanNode getRoot() {
return root; return root;
} }
public HashMap<Integer, Double> getSymbolProbabilityMap() {
return createSortedHashMap(symbolProbabilityMap);
}
private HashMap<Integer, Double> createSortedHashMap(HashMap<Integer, Double> map) {
List<Map.Entry<Integer, Double>> list = new LinkedList<Map.Entry<Integer, Double>>(map.entrySet());
//Custom Comparator
list.sort(new Comparator<Map.Entry<Integer, Double>>() {
@Override
public int compare(Map.Entry<Integer, Double> t0, Map.Entry<Integer, Double> t1) {
return -(t0.getValue().compareTo(t1.getValue()));
}
});
//copying the sorted list in HashMap to preserve the iteration order
HashMap<Integer,Double> sortedHashMap = new LinkedHashMap<Integer,Double>();
for (Map.Entry<Integer, Double> entry : list) {
sortedHashMap.put(entry.getKey(), entry.getValue());
}
return sortedHashMap;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment