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; + } }