diff --git a/src/main/java/azgracompress/compression/CompressorDecompressorBase.java b/src/main/java/azgracompress/compression/CompressorDecompressorBase.java
index 2c5bf47e0c65debd3453637bba06cbb9f1ef3a11..50416a8d6ef467d947fd61f17a4fc22d932abbd1 100644
--- a/src/main/java/azgracompress/compression/CompressorDecompressorBase.java
+++ b/src/main/java/azgracompress/compression/CompressorDecompressorBase.java
@@ -6,6 +6,8 @@ import azgracompress.huffman.Huffman;
import azgracompress.io.OutBitStream;
import java.io.DataOutputStream;
+import java.util.Iterator;
+import java.util.Map;
public abstract class CompressorDecompressorBase {
public static final int LONG_BYTES = 8;
@@ -30,6 +32,20 @@ public abstract class CompressorDecompressorBase {
protected Huffman createHuffmanCoder(final int[] symbols, final long[] frequencies) {
Huffman huffman = new Huffman(symbols, frequencies);
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;
}
diff --git a/src/main/java/azgracompress/huffman/Huffman.java b/src/main/java/azgracompress/huffman/Huffman.java
index 8a13ebfbef2cf84a04b0a671b52222d013b5dde9..771efbc5fa19682215b8812747ee417fa473f743 100644
--- a/src/main/java/azgracompress/huffman/Huffman.java
+++ b/src/main/java/azgracompress/huffman/Huffman.java
@@ -1,14 +1,13 @@
package azgracompress.huffman;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.PriorityQueue;
+import java.util.*;
public class Huffman {
- HuffmanNode root = null;
- HashMap<Integer, boolean[]> symbolCodes;
- final int[] symbols;
- final long[] symbolFrequencies;
+ private HuffmanNode root = null;
+ private HashMap<Integer, boolean[]> symbolCodes;
+ private HashMap<Integer, Double> symbolProbabilityMap;
+ private final int[] symbols;
+ private final long[] symbolFrequencies;
public Huffman(int[] symbols, long[] symbolFrequencies) {
assert (symbols.length == symbolFrequencies.length) : "Array lengths mismatch";
@@ -29,8 +28,6 @@ public class Huffman {
parentB.getProbability()));
assert (parentA.getProbability() <= parentB.getProbability());
}
- assert (parentA != null && parentB != null);
-
parentA.setBit(1);
parentB.setBit(0);
@@ -81,6 +78,7 @@ public class Huffman {
}
private PriorityQueue<HuffmanNode> buildPriorityQueue() {
+ symbolProbabilityMap = new HashMap<>(symbols.length);
double totalFrequency = 0.0;
for (final long symbolFrequency : symbolFrequencies) {
totalFrequency += symbolFrequency;
@@ -90,6 +88,7 @@ public class Huffman {
for (int sIndex = 0; sIndex < symbols.length; sIndex++) {
final double symbolProbability = (double) symbolFrequencies[sIndex] / totalFrequency;
+ symbolProbabilityMap.put(symbols[sIndex], symbolProbability);
queue.add(new HuffmanNode(symbols[sIndex], symbolProbability, symbolFrequencies[sIndex]));
}
@@ -104,4 +103,25 @@ public class Huffman {
public HuffmanNode getRoot() {
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;
+ }
}