The document defines classes for building a Huffman coding tree from character frequencies in a file. It includes classes for a frequency table, priority queue, tree nodes, and the Huffman algorithm. The Huffman class constructs the tree from a file, inserts codewords, and can encode and decode a string using the tree. It outputs entropy and average code length metrics.
Kodo Millet PPT made by Ghanshyam bairwa college of Agriculture kumher bhara...
Table.java Huffman code frequency tableimport java.io.;im.docx
1. // Table.java: Huffman code frequency table
import java.io.*;
import java.util.TreeSet
class Table {
public final int MAXT = 100; // maximum number of different
symbols
public int currTableSize; // current size as table is constructed
public Entry[] tab; // the table array, not allocated
private Reader in; // internal file name for input stream
String file = ""; // the whole input file as a String
private boolean fileOpen = false; // is the file open yet?
private String fileName; // name of input file, if present
private int totalChars = 0; // total number of chars read
char markerChar = '@'; // sentinal at end of file
// Table: constructor, input parameter: input file name or null
public Table(String f) {
fileName = f;
currTableSize = 0;
tab = new Entry[MAXT];
}
// dumpTable: debug dump of contents of Table
public void dumpTable() {
int i;
System.out.println("nDump of Table ----->");
System.out.println(" Size: " + currTableSize);
for (i = 0; i < currTableSize; i++) {
System.out.println("Entry " + i + ". Symbol: " +
tab[i].symb + ", Weight: " + tab[i].weight +
", Representation: " + tab[i].rep);
}
System.out.println("----> End Dump of Tablen");
}
2. // getNextChar: fetches next char. Also opens input file
private char getNextChar() {
char ch = ' '; // = ' ' to keep compiler happy
if (!fileOpen) {
fileOpen = true;
if (fileName == null)
in = new InputStreamReader(System.in);
else {
try {
in = new FileReader(fileName);
} catch (IOException e) {
System.out.println("Exception opening " + fileName);
}
}
}
try {
ch = (char)in.read();
} catch (IOException e) {
System.out.println("Exception reading character");
}
return ch;
}
// buildFromFile: read file and build the map of the character
frequencies
private void buildFromFile(File file) throws
FileNotFoundException {
//
Map<String, Integer> freqMap = new BSTMap<String,
Integer>();Scanner scanner = new Scanner(file);
scanner.useDelimiter("");
String character;
while (scanner.hasNext()){
character = scanner.next();
Integer count = freqMap.get(character);
3. if (count == null){
count = Integer.valueOf(0);
}
freqMap.put(character, count+1);
}
// for each key, make a tree and load it into the priority queue
PriorityQueue<BinaryTree<CountPair>> treeQueue = new
PriorityQueue<BinaryTree<CountPair>>(freqMap.keySet().size(
), new CountPairTreeComparator
BinaryTree<CountPair> tmpTree;
for (String key: freqMap.keySet()){
int frequency = freqMap.get(key);
tmpTree = new BinaryTree<CountPair>(null, new
CountPair(key, frequency), null);
treeQueue.add(tmpTree);
}
Public interface Map<K extends Comparable<K>,V>
{
//This should load the value value into the map at the location
//associated with the key, replacing any preexisting value
//already associated with the key.
void put(K key, V value)
{
Map<String, Integer> freqMap = new BSTMap<String,
Integer>();Scanner scanner = new Scanner(file);
scanner.useDelimiter("");
String character;
while (scanner.hasNext()){
character = scanner.next();
Integer count = freqMap.get(character);
if (count == null){
count = Integer.valueOf(0);
}
freqMap.put(character, count+1);
}}
4. //This should fetch the value V associated with the key key, or
//null, if no match can be found.
int V get(K key)
{
int e = freqMap.get(key);
List l = new ListNode;
if( l.nextList.compareTo(e) != null){
V = e;
return V;
}
//This will report if there is a value associated with the value
//key in the map.
boolean containsKey(K key)
{
int e = freqMap.get(key);
List l = new ListNode;
if( l.nextList.compareTo(e) != null){
return true;
else
{
return false;
}
//This method should remove the entry associated with key and
//return the associated value. Return null if the key is
//not found.
public V remove(K key)
{
int e = freqMap.get(key);
List l = new ListNode;
if( l.nextList.compareTo(e) != null){
l.nextList = null;
return e;
}
else
{
return null;
5. }}
//This method should return a Set of all available keys in the
//map. You may use the java.util.TreeSet class to return
//these. You can build these on the fly using a traversal, or
//collect them as new keys are added to the map.
Set<K> keySet()
{
BinaryTree<CountPair> tmpTree;
while (void put(K key, V value) = 0)
{
Return K;
}}
//buildFromFile: fetch each character and build the Table
public void buildTable() {
char ch = getNextChar();
while (ch != 65535 && ch != markerChar) { // EOF or
special sentinal #
totalChars++;
file += ch;
int i = lookUp(ch);
if (i == -1) { // new entry
tab[currTableSize] = new Entry();
tab[currTableSize].symb = ch;
tab[currTableSize].weight = 1.0;
tab[currTableSize].rep = "";
currTableSize++;
}
else { // existing entry
tab[i].weight += 1.0;
}
// System.out.print(ch); // for debug
ch = getNextChar();
} // while
// finish calculating the weights
for (int j = 0; j < currTableSize; j++)
tab[j].weight /= (double)totalChars;
6. // System.out.println(); // for debug
}
// lookUp: loop up the next char in the Table tab
public int lookUp(char ch) {
for (int j = 0; j < currTableSize; j++)
if (tab[j].symb == ch) return j;
return -1;
}
// log2: Logarithm base 2
public double log2(double d) {
return Math.log(d) / Math.log(2.0);
}
// entropy: calculate entropy of the Table
public double entropy() {
double res = 0.0;
for (int i = 0; i < currTableSize; i++)
res += tab[i].weight * log2(1.0/tab[i].weight);
return res;
}
// aveCodeLen: calculate average code length
public double aveCodeLen() {
double res = 0.0;
for (int i = 0; i < currTableSize; i++)
res += tab[i].weight * tab[i].rep.length();
return res;
}
}
// TreeNode.java: node in the Huffman tree, used for
encode/decode
class TreeNode {
7. public double weight; // probability of symb occurring
public char symb; // the symbol to be encoded
public String rep; // string of 0's and 1's, the huffman code
word
public TreeNode left, right; // tree pointeres
public int step; // step number in construction (just for
displaying tree)
}
// ListNode.java: node in the linked list of trees, initially root
node trees
class ListNode {
public TreeNode hufftree;
public ListNode next;
}
// PriorityQueue.java: implement a priority queue as a linked
list of trees
// Initialize it as a linked list of singleton trees
class PriorityQueue {
private int initialCapacity;
public PriorityQueue(int initialCapacity,Comparator<? super E>
comparator)
{
ListNode list = null; // this points to the main list
// insert: void add(E item) insert new entry into the list
public void insert(TreeNode t) {
ListNode l = new ListNode();
l.hufftree = t;
l.next = list;
list = l;
}
//Obviously, this says if the queue is empty or not.
8. public boolean isEmpty()
{
ListNode l = new ListNode();
l.hufftree = t;
if(l.next == null)
{
Return true;
}
else
{
Return false;
}
list = l;
}
//This should return the size of the queue.
public int size()
{
int count = 0;
ListNode l = new ListNode();
if(l.hasnext()){
count++;
return count;
}
// buildList: create the initial list with singleton trees
public void buildList(Entry[] tab, int n) {
int i;
TreeNode tNode;
for (i = 0; i < n; i++) {
tNode = new TreeNode();
tNode.weight = tab[i].weight;
tNode.left = tNode.right = null;
tNode.symb = tab[i].symb;
tNode.rep = "";
insert(tNode);
9. }
}
//This returns the next item without removing it. This returns
//null if the queue is empty.
public E peek()
{
ListNode l = list;
while (l != null) {
return l.next;
}
// dumpList: debug dump of the list
public void dumpList() {
System.out.println("nDump of List ----->");
ListNode l = list;
while (l != null) {
System.out.print("Symb: " + l.hufftree.symb);
System.out.println(", Weight: " + l.hufftree.weight);
l = l.next;
}
System.out.println("----> End Dump of Listn");
}
//This removes the first item from the queue.
public E remove()
{
ListNode l;
if(l != null) {
l.next == null;
}
// least: Remove and return from the list tree with greatest
root weight
// sort of a pain in the ass to write
public TreeNode least() {
ListNode l, oldl, minl = null, oldminl = null; // = null: for
compiler
10. double minw = 1000000;
oldl = list;
l = list;
while (l != null) {
if (l.hufftree.weight < minw) {
minw = l.hufftree.weight;
oldminl = oldl;
minl = l;
}
oldl = l;
l = l.next;
}
if (minl == oldminl) {
list = list.next;
return minl.hufftree;
}
oldminl.next = minl.next;
return minl.hufftree;
}
}
// Huffman.java: the Huffman tree algorithm
import java.text.DecimalFormat;
class Huffman {
public TreeNode tree; // the decoding tree
public Table t; // the frequency and encoding table
public PriorityQueue p; // priority queue for building the
Huffman tree
private int depth; // depth variable for debug printing of tree
String encodedFile, decodedFile; // files as Strings
char markerChar = '@'; // sentinal at end of file
public DecimalFormat fourDigits = new
DecimalFormat("0.0000");
// Huffman: constructor, does all the work
11. public Huffman(String fileName) {
t = new Table(fileName);
t.buildTable();
// t.dumpTable();
p = new PriorityQueue();
p.buildList(t.tab, t.currTableSize);
// p.dumpList();
tree = huffman(t.currTableSize);
insertRep(tree, t.tab, t.currTableSize, "");
displayTree(tree);
t.dumpTable();
// System.out.println("nInput file (as a String):");
// System.out.println(t.file);
encodedFile = encode(t.file);
// System.out.println("nEncoded file (as a String):");
// System.out.println(encodedFile);
// decodedFile = decode(encodedFile);
// System.out.println("nDecoded file (as a String):");
// System.out.println(decodedFile);
System.out.println("Entropy: " + t.entropy() +
", Ave. Code Length: " + t.aveCodeLen());
}
// encode: translate the input file to binary Huffman file
public String encode(String file) {
String returnFile = ""; // encoded file to return (as a String)
for (int i = 0; i < file.length(); i++) {
int loc = t.lookUp(file.charAt(i));
if (loc == -1) {
System.out.println("Error in encode: can't find: " +
file.charAt(i));
System.exit(0);
}
returnFile += t.tab[loc].rep;
}
return returnFile;
12. }
// decode: translate the binary file (as a string) back to chars
public String decode(String file) {
String returnFile = ""; // decoded file to return (as a String)
TreeNode treeRef; // local tree variable to keep chasing into
tree
int i = 0; // index in the Huffman String
while (i < file.length()) { // keep going to end of String
treeRef = tree; // start at root of tree
while (true) {
if (treeRef.symb != markerChar) { // at a leaf node
returnFile += treeRef.symb;
break;
}
else if (file.charAt(i) == '0') { // go left with '0'
treeRef = treeRef.left;
i++;
}
else { // go right with '1'
treeRef = treeRef.right;
i++;
}
} // while (true)
} // while
return returnFile;
}
// huffman: construct the Huffman tree, for decoding
public TreeNode huffman(int n) {
int i;
TreeNode tree = null; // = null for compiler
for (i = 0; i < n-1; i++) {
tree = new TreeNode();
tree.left = p.least();
tree.left.step = i + 1; // just for displaying tree
13. tree.right = p.least();
tree.right.step = i + 1; // just for displaying tree
tree.weight = tree.left.weight +
tree.right.weight;
tree.symb = markerChar; // must not use '@' in input //file
tree.rep = "";
p.insert(tree);
}
return tree;
}
// displayTree: print out the tree, with initial and final
comments
public void displayTree(TreeNode tree) {
System.out.println("nDisplay of Huffman coding treen");
depth = 0;
displayTreeRecurs(tree);
}
// displayTreeRecurs: need recursive function for inorder
traveral
public void displayTreeRecurs(TreeNode tree) {
depth++; // depth of recursion
String s = "";
if (tree != null) {
s = display(tree.rep + "0");
System.out.println(s);
displayTreeRecurs(tree.left);
s = display(tree.rep);
System.out.print(s + "+---");
if (depth != 1) {
if (tree.symb == markerChar) System.out.print("+---");
}
System.out.print(tree.symb + ": " +
fourDigits.format(tree.weight) + ", " + tree.rep);
if (depth != 1)
14. System.out.println(" (step " + tree.step + ")");
else System.out.println();
displayTreeRecurs(tree.right);
s = display(tree.rep + "1");
System.out.println(s);
}
depth--;
}
// display: output blanks and verical lines to display tree
private String display(String rep) {
// tricky use of rep string to display correctly
String s = " ";
for (int i = 0; i < rep.length() - 1; i++) { // initial chars
if (rep.charAt(i) != rep.charAt(i+1) ) s += "|";
else s += " ";
s += " ";
}
return s;
}
// insertRep: tricky function to use Huffman tree to create
representation
public void insertRep(TreeNode tree, Entry tab[], int n, String
repr) {
//recursive function to insert Huffman codewords at each
node.
// this could just insert at the leaves.
String s1, s2;
tree.rep = repr;
if ((tree.left) == null && (tree.right) == null) {
for (int i = 0; i < n; i++)
if (tree.symb == tab[i].symb)
tab[i].rep = tree.rep;
return;
}
15. s1 = repr;
s1 += "0";
insertRep(tree.left, tab, n, s1); // recursive call to the left
s2 = repr;
s2 += "1";
insertRep(tree.right, tab, n, s2); // recursive call to the right
}
// main: doesn't do much; just feeds in input file name
public static void main(String[] args) {
Huffman huff;
// pass an input file name if present on command line
if (args.length > 0)
huff = new Huffman(args[0]);
else
huff = new Huffman(null);
}
}