Modify HuffmanTree.java and HuffmanNode.java to allow the user to se.pdf
1. Modify HuffmanTree.java and HuffmanNode.java to allow the user to select the value of n 9 to
construct an n ary Huffman Tree. Once finished, verify the accuracy of your tree by running it
for the English Alphabet for n = 3, 4, 5, 6, 7, 8, 9. For each value of n, compute the average
codeword length. Write these in a table (n vs. ACW L(Cn)).
/ HuffmanTree.java
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Scanner;
public class HuffmanTree {
public static void main(String[] args){
Scanner in = new Scanner(System.in);
System.out.print("Enter the file name: ");
String fileName = in.nextLine();
ArrayList nodes = new ArrayList<>();
ArrayList temp = new ArrayList<>();
try {
Scanner fin = new Scanner(new FileReader(fileName));
String symbol;
double prob;
while(fin.hasNext()){
symbol = fin.next();
prob = fin.nextDouble();
nodes.add(findInsertIndex(nodes, prob), new HuffmanNode(symbol, prob));
}
fin.close();
temp.addAll(nodes);
HuffmanNode root = createHuffmanTree(temp);
setCodeWords(root);
double avg = 0;
for (HuffmanNode node : nodes) {
System.out.println(node.getS() + ": " + node.getC() + ": " + node.getL());
avg += node.getL();
3. root.setC(codeWord);
root.setL(codeWord.length());
}
else{
setCodeWords(root.getLeft(), codeWord + "0");
setCodeWords(root.getRight(), codeWord + "1");
}
}
private static int findInsertIndex(ArrayList nodes, double prob){
for(int i = 0; i < nodes.size(); ++i){
if(prob < nodes.get(i).getP()){
return i;
}
}
return nodes.size();
}
}
// HuffmanNode.java
public class HuffmanNode {
private String S;
private double P;
private String C;
private int L;
private HuffmanNode left, right;
public HuffmanNode(String s, double p) {
S = s;
P = p;
}
public String getS() {
return S;
}
4. public void setS(String s) {
S = s;
}
public double getP() {
return P;
}
public void setP(double p) {
P = p;
}
public String getC() {
return C;
}
public void setC(String c) {
C = c;
}
public int getL() {
return L;
}
public void setL(int l) {
L = l;
}
public HuffmanNode getLeft() {
return left;
}
public void setLeft(HuffmanNode left) {
this.left = left;
}
5. public HuffmanNode getRight() {
return right;
}
public void setRight(HuffmanNode right) {
this.right = right;
}
}
//EnglishAlphabet.txt (symbols with probability)
Solution
public final class Huffman { private Huffman() {}; private static class HuffmanNode {
char ch; int frequency; HuffmanNode left; HuffmanNode right;
HuffmanNode(char ch, int frequency, HuffmanNode left, HuffmanNode right) { this.ch
= ch; this.frequency = frequency; this.left = left; this.right = right; }
} private static class HuffManComparator implements Comparator { @Override
public int compare(HuffmanNode node1, HuffmanNode node2) { return node1.frequency
- node2.frequency; } } /** * Compresses the string using huffman algorithm. *
The huffman tree and the huffman code are serialized to disk * * @param sentence
The sentence to be serialized * @throws FileNotFoundException If file is not found *
@throws IOException If IO exception occurs. */ public static void
compress(String sentence) throws FileNotFoundException, IOException { if (sentence ==
null) { throw new NullPointerException("Input sentence cannot be null."); } if
(sentence.length() == 0) { throw new IllegalArgumentException("The string should
atleast have 1 character."); } final Map charFreq = getCharFrequency(sentence);
final HuffmanNode root = buildTree(charFreq); final Map charCode =
generateCodes(charFreq.keySet(), root); final String encodedMessage =
encodeMessage(charCode, sentence); serializeTree(root);
serializeMessage(encodedMessage); } private static Map getCharFrequency(String
sentence) { final Map map = new HashMap(); for (int i = 0; i < sentence.length(); i++)
{ char ch = sentence.charAt(i); if (!map.containsKey(ch)) { map.put(ch,
1); } else { int val = map.get(ch); map.put(ch, ++val); } }
return map; } /** * Map map * Some implementation of that treeSet is passed
as parameter. * @param map */ private static HuffmanNode buildTree(Map map) {
final Queue nodeQueue = createNodeQueue(map); while (nodeQueue.size() > 1) {
6. final HuffmanNode node1 = nodeQueue.remove(); final HuffmanNode node2 =
nodeQueue.remove(); HuffmanNode node = new HuffmanNode('0', node1.frequency
+ node2.frequency, node1, node2); nodeQueue.add(node); } // remove it to
prevent object leak. return nodeQueue.remove(); } private static Queue
createNodeQueue(Map map) { final Queue pq = new PriorityQueue(11, new
HuffManComparator()); for (Entry entry : map.entrySet()) { pq.add(new
HuffmanNode(entry.getKey(), entry.getValue(), null, null)); } return pq; }
private static Map generateCodes(Set chars, HuffmanNode node) { final Map map = new
HashMap(); doGenerateCode(node, map, ""); return map; } private static void
doGenerateCode(HuffmanNode node, Map map, String s) { if (node.left == null &&
node.right == null) { map.put(node.ch, s); return; }
doGenerateCode(node.left, map, s + '0'); doGenerateCode(node.right, map, s + '1' ); }
private static String encodeMessage(Map charCode, String sentence) { final StringBuilder
stringBuilder = new StringBuilder(); for (int i = 0; i < sentence.length(); i++) {
stringBuilder.append(charCode.get(sentence.charAt(i))); } return
stringBuilder.toString(); } private static void serializeTree(HuffmanNode node) throws
FileNotFoundException, IOException { final BitSet bitSet = new BitSet(); try
(ObjectOutputStream oosTree = new ObjectOutputStream(new
FileOutputStream("/Users/ap/Desktop/tree"))) { try (ObjectOutputStream oosChar =
new ObjectOutputStream(new FileOutputStream("/Users/ap/Desktop/char"))) {
IntObject o = new IntObject(); preOrder(node, oosChar, bitSet, o);
bitSet.set(o.bitPosition, true); // padded to mark end of bit set relevant for deserialization.
oosTree.writeObject(bitSet); } } } private static class IntObject { int
bitPosition; } /* * Algo: * 1. Access the node * 2. Register the value in bit set.
* * * here true and false dont correspond to left branch and right branch. * there, *
- true means "a branch originates from leaf" * - false mens "a branch originates from non-
left". * * Also since branches originate from some node, the root node must be provided
as source * or starting point of initial branches. * * Diagram and how an bit set
would look as a result. * (source node) * / * true
true * / * (leaf node) (leaf node) * | | *
false false * | | * * So now a bit set looks like
[false, true, false, true] * */ private static void preOrder(HuffmanNode node,
ObjectOutputStream oosChar, BitSet bitSet, IntObject intObject) throws IOException { if
(node.left == null && node.right == null) { bitSet.set(intObject.bitPosition++, false); //
register branch in bitset oosChar.writeChar(node.ch); return;
// DONT take the branch. } bitSet.set(intObject.bitPosition++, true); // register
7. branch in bitset preOrder(node.left, oosChar, bitSet, intObject); // take the branch.
bitSet.set(intObject.bitPosition++, true); // register branch in bitset
preOrder(node.right, oosChar, bitSet, intObject); // take the branch. } private static void
serializeMessage(String message) throws IOException { final BitSet bitSet =
getBitSet(message); try (ObjectOutputStream oos = new ObjectOutputStream(new
FileOutputStream("/Users/ap/Desktop/encodedMessage"))){ oos.writeObject(bitSet);
} } private static BitSet getBitSet(String message) { final BitSet bitSet = new
BitSet(); int i = 0; for (i = 0; i < message.length(); i++) { if (message.charAt(i)
== '0') { bitSet.set(i, false); } else { bitSet.set(i, true); }
} bitSet.set(i, true); // dummy bit set to know the length return bitSet; } /** *
Retrieves back the original string. * * * @return The original
uncompressed string * @throws FileNotFoundException If the file is not found *
@throws ClassNotFoundException If class is not found * @throws IOException If
IOException occurs */ public static String expand() throws FileNotFoundException,
ClassNotFoundException, IOException { final HuffmanNode root = deserializeTree();
return decodeMessage(root); } private static HuffmanNode deserializeTree() throws
FileNotFoundException, IOException, ClassNotFoundException { try (ObjectInputStream
oisBranch = new ObjectInputStream(new FileInputStream("/Users/ap/Desktop/tree"))) {
try (ObjectInputStream oisChar = new ObjectInputStream(new
FileInputStream("/Users/ap/Desktop/char"))) { final BitSet bitSet = (BitSet)
oisBranch.readObject(); return preOrder(bitSet, oisChar, new IntObject()); }
} } /* * Construct a tree from: * input [false, true, false, true, (dummy true to mark
the end of bit set)] * The input is constructed from preorder traversal * * Algo: * 1
Create the node. * 2. Read what is registered in bitset, and decide if created node is supposed
to be a leaf or non-leaf * */ private static HuffmanNode preOrder(BitSet bitSet,
ObjectInputStream oisChar, IntObject o) throws IOException { // created the node before
reading whats registered. final HuffmanNode node = new HuffmanNode('0', 0, null,
null); // reading whats registered and determining if created node is the leaf or non-leaf.
if (!bitSet.get(o.bitPosition)) { o.bitPosition++; // feed the next position to the
next stack frame by doing computation before preOrder is called. node.ch =
oisChar.readChar(); return node; } o.bitPosition = o.bitPosition + 1; // feed
the next position to the next stack frame by doing computation before preOrder is called.
node.left = preOrder(bitSet, oisChar, o); o.bitPosition = o.bitPosition + 1; // feed the next
position to the next stack frame by doing computation before preOrder is called. node.right
= preOrder(bitSet, oisChar, o); return node; } private static String
decodeMessage(HuffmanNode node) throws FileNotFoundException, IOException,
8. ClassNotFoundException { try (ObjectInputStream ois = new ObjectInputStream(new
FileInputStream("/Users/ameya.patil/Desktop/encodedMessage"))) { final BitSet bitSet
= (BitSet) ois.readObject(); final StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < (bitSet.length() - 1);) { HuffmanNode temp = node; //
since huffman code generates full binary tree, temp.right is certainly null if temp.left is null.
while (temp.left != null) { if (!bitSet.get(i)) { temp = temp.left;
} else { temp = temp.right; } i = i + 1;
} stringBuilder.append(temp.ch); } return stringBuilder.toString();
} } public static void main(String[] args) throws FileNotFoundException, IOException,
ClassNotFoundException { // even number of characters Huffman.compress("some");
Assert.assertEquals("some", Huffman.expand()); // odd number of characters
Huffman.compress("someday"); Assert.assertEquals("someday", Huffman.expand());
// repeating even number of characters + space + non-ascii Huffman.compress("some
some#"); Assert.assertEquals("some some#", Huffman.expand()); // odd number of
characters + space + non-ascii Huffman.compress("someday someday&");
Assert.assertEquals("someday someday&", Huffman.expand()); } }