I am trying to build a binary tree from a string input piped to System.in with Java. Whenever a letter from a-z is encountered in the string I am making an internal node (with 2 children). Whenever a 0 is encountered in the string I am making an external node (a leaf). The string is in preorder, so just as an example, if I had an input such as:
abcd000e000
I am supposed to make the following binary tree
a
/ \
b 0
/ \
c e
/ \ / \
d 00 0
/ \
0 0
At least that is what I think I am supposed to make according to the assignment details (in a link below). We were also given sample input and output for the entire program:
Input
a0
0
a00
ab000
Output
Tree 1:
Invalid!
Tree 2:
height: -1
path length: 0
complete: yes
postorder:
Tree 3:
height: 0
path length: 0
complete: yes
postorder: a
Tree 4:
height: 1
path length: 1
complete: yes
postorder: ba
I am trying to implement a program that will do this for me with Java, but I don't think I am making the binary tree correctly. I have provided the code I have come up with so far and detailed in the comments above each method what trouble I have run into so far while debugging. If more context is needed the following link details the entire assignment and what the ultimate goal is supposed to be (building the binary tree is only the first step, but I'm stuck on it):
Link to Assignment
import java.io.*;
// Node
class TreeNode {
char value;
TreeNode left;
TreeNode right;
}
// Main class
public class btsmall {
// Global variables
char[] preorder = new char[1000];
int i = 0;
// Main method runs gatherOutput
public static void main(String[] args) throws IOException {
new btsmall().gatherOutput();
}
// This takes tree as input from the gatherOutput method
// and whenever a 0 is encountered in the preorder character array
// (from a string from System.in) a new external node is created with
// a value of 0. Whenever a letter is encountered in the character
// array, a new internal node is created with that letter as the value.
//
// When I debug through this method, the tree "appears" to be made
// as expected as the tree.value is the correct value, though I
// can't check the tree.left or tree.right values while debugging
// as the tree variable seems to get replaced each time the condition
// checks restart.
public void createTree(TreeNode tree) throws IOException {
// Check that index is not out of bounds first
if (i >= preorder.length) {
i++;
} else if (preorder[i] == '0') {
tree = new TreeNode();
tree.value = '0';
tree.left = tree.right = null;
i++;
} else {
tree = new TreeNode();
tree.value = preorder[i];
i++;
createTree(tree.left);
createTree(tree.right);
}
}
// Supposed to print out contents of the created binary trees.
// Intended only to test that the binary tree from createTree()
// method is actually being created properly.
public void preorderTraversal(TreeNode tree) {
if (tree != null) {
System.out.println(tree.value + " ");
preorderTraversal(tree.left);
preorderTraversal(tree.right);
}
}
// Reads System.in for the Strings used in making the binary tree
// and is supposed to make a different binary tree for every line of input
//
// While debugging after the createTree method runs, the resulting tree variable
// has values of tree.left = null, tree.right = null, and tree.value has no value
// (it's just a blank space).
//
// This results in preorderTraversal printing out a single square (or maybe the square
// is some character that my computer can't display) to System.out instead of all
// the tree values like it's supposed to...
public void gatherOutput() throws IOException {
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(input);
String line = null;
TreeNode tree = new TreeNode();
while ((line = reader.readLine()) != null) {
preorder = line.toCharArray();
createTree(tree);
preorderTraversal(tree);
i = 0;
}
}
}
Can anyone help me with building the binary tree properly and point out what I am doing wrong that would result in the output I'm currently getting? Am I at least on the right track? Any hints?
Thanks.
EDIT:
Here's a picture of the "square" output (this is in Eclipse).
Your createTree() method ... doesn't create a tree.
You never attach internal nodes to anything ... you just create them, insert the value, then pass them to the next createTree() call (which does the same).
A quick fix can be a simple modification of your createTree(..) method,
public void createTree(TreeNode tree) throws IOException {
// Check that index is not out of bounds first
if (i >= preorder.length) {
i++;
} else if (preorder[i] == '0') {
tree.value = '0';
tree.left = tree.right = null;
i++;
} else {
tree.value = preorder[i];
i++;
tree.left = new TreeNode();
createTree(tree.left);
tree.right = new TreeNode();
createTree(tree.right);
}
}
Notice you were creating a TreeNode inside this method, whereas it was already passed as an argument. So, you were not at all using the same. Whatever you did was not in the original TreeNode passed.
NB: Not arguing about the correctness of binary tree. Just fix a problem in hand. This might help the OP.
but I don't think I am making the binary tree correctly
Yes, it is incorrect. In binary tree one sub-tree is "less" than current element, another one is "more". You have, for example, "b" as the parent for "c" and "e", while (if followed natural sorting) both "c" and "e" are "more".
You need to rebalance you tree in the process.
P.S. I don't know what zeros supposed to mean in the input, but if the input is limited the simplest way to build a binary tree from a sorted sequence is:
load whole sequence into an array
get middle element as the root one
repeat step 2 recursively for the sub-arrays on the left and right of the root element
Update
And yes, as stated in some other answer, you need to have something like:
} else if (preorder[i] == '0') {
TreeNode subTree = new TreeNode();
subTree.value = '0';
tree.rigth = subTree;
i++;
and then pass subTree into recursive call.
Also I see an implementation problem:
while ((line = reader.readLine()) != null) {
does not seem to be a correct stop condition. It will loop forever because if you press just enter, line will not be null, but an empty string.
This one is more suitable:
while (!(line = reader.readLine()).equals("")) {
Related
I'm having a hard time figuring out how to create an adjacency matrix from an input file. The input file is supposed to represent a directed, weighted graph of nodes.
The purpose is to create a program that can do a iterative depth first search, but I'm really stuck on the data input part of the assignment.
The input text file would supposedly look like the following:
each node is represented by two lines of text. For example the on the very top line, the first 'S' is the name of the node, the second 'S' indicates that it's a start node, the third 'n' indicates that it's a regular node, not a goal node, which would be indicated by a 'g'.
On the second line are the two nodes connected to 'S' the first being 'B' with a weighted distance of 1, and the second being 'E' with a weighted distance of 2.
The third line is supposed to be blank, and the pattern is repeated.
S S n
B 1 E 2
B N n
C 2 F 3
C N n
D 2 GA 4
D N n
GA 1
E N n
B 1 F 3 H 6
F N n
I 3 GA
3 C 1
GA N g
H N n
I 2 GB 2 F 1
I N n
GA 2 GB 2
GB N g
I'm really stuck on this. I have been using buffered reader to scan in the file but I've been wondering if using Scanner would be easier.
I'm currently attempting to create Node objects with the attributes of having a name, and maybe a link to other adjacent Node objects using a linked list of some kind. I've also considered using an array of node objects but I'm really unsure how to represent which nodes connect to which other nodes and how to build that into an adjacency matrix using a two dimensional array.
Any suggestions would be greatly appreciated, I'm a newbie so I apologize if my question is not of academic importance to others
Edit: my code is something like this:
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == openButton)
{
returnVal = fileChooser.showOpenDialog(null);
if(returnVal == JFileChooser.APPROVE_OPTION)
{
selected_file = fileChooser.getSelectedFile();
String file_name = fileChooser.getSelectedFile().getName();
file_name = file_name.substring(0, file_name.indexOf('.'));
try
{
BufferedWriter buff_writer = null;
File newFile = new File("."+file_name+"_sorted.txt");
boolean verify_creation = newFile.createNewFile();
//if (verify_creation)
// System.out.println("file created successfully");
//else
// System.out.println("file already present in specified location");
file_reader1 = new BufferedReader(new FileReader(selected_file));
file_reader2 = new BufferedReader(new FileReader(selected_file));
FileWriter file_writer = new FileWriter(newFile.getAbsoluteFile());
buff_writer = new BufferedWriter(file_writer);
//find the number of nodes in the file
while( (currentLine = file_reader1.readLine()) != null)
{
k++;
System.out.println("value of k: " + k);
}
nodeArray = new Node[k];
while( (currentLine = file_reader2.readLine()) != null)
{
//System.out.print(currentLine);
String[] var = currentLine.split(" ");
nodeArray[x] = new Node(var[0], var[1], var[2]);
nodeArray[x].setLink1(new Node(var[3], null, null));
}
buff_writer.close();
file_writer.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
}
Edit #2
my node object looks something like this:
public Node(String n, String t1, String t2)
{
name = n;
type1 = t1;
type2 = t2;
link1 = null;
link2 = null;
link3 = null;
link4 = null;
link5 = null;
link6 = null;
Thing is: you do not want to use a two-dimensional array here. You want to step back and design/model a class/data structure that fits the "actual problem" you are working.
In other words: your problem is about representing a graph of nodes and edges. So, some tips to get you going ..
Lets start with:
enum NodeType { START, GOAL, NORMAL ; }
public class Node {
private final String name;
public Node(String name) {
this.name = name;
The above gives you a reasonable way to distinguish the different types of nodes. And then we start with the representation of a node. Obviously, its name is fixed - you dont want to change the name of a node after it was created. Then you have setters like
public void setType(NodeType type) ...
And more fields,
private final Map<Node, Integer> neighbors = new HashMap<>();
and a method to add a new neighbor:
public void addNeighborNode(Node node, int weight) {
neighbors.put(node, weight);
[ for the record: theoretically, you could create a class that takes all infos via a constructor, avoiding the need of having setter methods. that has certain advantages, but makes things more complicated; and I guess ... what I am showing you here is complicated enough already ;-) ]
The whole idea here - you separate the PARSING from the way how you represent/build your objects. Of course, at some point you have to read that strings, to then build node objects from them.
But you better start with a Node class like above, because then you can build a graph ... without the need to parse a text file:
Node n1 = new Node("n1");
n1.setType(NodeType.START);
Node n2 = new Node("n2");
n2.setType(NodeType.GOAL);
n1.setNeighborNode(n2, 5);
In other words: first you build a nice "class model" for a graph. And you can write test code like above. And when all of that works; then you write the code that reads that input file and translates that into the method calls you need to build your graph!
Long story short: of course, parsing that text file is important, but you should not focus on that. Instead: think a lot about the class model of your data first. That is were you can learn the most, and have the most fun in experimenting. Pulling in strings and turning them into objects, that is just "work". Have some fun first!
Given a Binary Tree I want to develop a recursive method that finds the bitcode for a specific character given the root of the tree (see diagram)
Suppose you had a Tree Class where every tree had 4 fields [Left Tree, Right Tree, Left Leaf, Right Leaf] where every branch either led to another tree or a leaf (char value).
String result = traverse(root, 'c', ""); //1011
public static String traverse(Tree t, char target, String bitcode){
String b = bitcode;
if (t.leftleaf != null){
if (t.leftleaf == target) {
b += "0";
}
}
if (t.rightleaf != null){
if (t.rightleaf == target){
b += "1";
}
}
if (t.lefttree != null){
b += "0" + traverse(t.lefttree,target, b);
}
if (t.righttree != null){
b += "1" + traverse(t.righttree,target, b);
}
return b;
}
However my method above does not work as expected. How can I rewrite it so it properly shows the bitcode?
The problem is that you are not handling the case where target is not found in a subtree. Even if target is not found in left tree, b += "0" + traverse(t.lefttree,target, b); will get executed. The same can be said when you traverse the right tree. In fact, your method will traverse the right tree even if target is found in the left tree already. The use of add assignment operator further manifests this problem.
Also note that this function does not require parameter String bitcode to work.
public static String findBitcode(Tree t, char target){
// See if target immediately available
if (t.leftleaf == target) return "0";
if (t.rightleaf == target) return "1";
// Search deeper
String leftResult = findBitcode(t.leftree, target);
if (leftResult != null) return "0" + leftResult;
String rightResult = findBitcode(t.righttree, target);
if (rightResult != null) return "1" + rightResult;
// Not found
return null;
}
You walk the tree from the root towards the leaves when you decode, i.e. when you go from binary code to character.
When you encode you either have to have an index of character leaves that you can then look up, and then have each tree node point to its parent so that you can generate the code (backwards) when going from the leaf to the root, or you can traverse the encoding tree once when constructed and build an encoding table where, for each possible input character, you have the final Huffman code to emit.
Given the alphabet and a morse code value for each letter...
a._
b_...
c_._.
d_.. //file to be read in
e.
f.._.
I'm attempting to create a tree, finding the position for a letter in the tree by scanning the code, and branching left for a dot and branching right for a dash.
I've created a node class with the typical numberNode left and numberNode right variables along with morseCode and letter. Here's my function.
aList is an arraylist of created nodes read in from a file. rootNode is the root of the tree, having no set letter or morsecode.
public static void createTree(ArrayList<numberNode> aList, numberNode rootNode)
{
for (numberNode n : aList) //for each numberNode in aList
{
int lengthOfCode = n.getmorseCode().length()-1; //get the length of the morsecode
numberNode currentNode = rootNode; //sets currentNode to the rootNode at first
for (int i=0; i<lengthOfCode; i++)
{
char c = n.getmorseCode().charAt(i); //for each char in morsecode until it gets to the end
if (c == '.')
{
if (currentNode.getleft() = null) //if currentnode left is null
{
numberNode newLeftNode = new numberNode(); //create new node
currentNode.setleft(newLeftNode); //set current node left to the new node
if (i == lengthOfCode)
{
currentNode.setleft(n); //if end of morse code, set the current node left's to n
}
else
{
currentNode = newLeftNode; //else change current node to the newly created leftnode
}
}
else //if current node left is not null
{
if (i == lengthOfCode)
{
currentNode.setleft(n); //if at end of morse code
}
currentNode = currentNode.getleft(); //if not at end set current node to current node's left
}
}
if (c == '_')
{
if (currentNode.right() =null)
{
numberNode newRightNode = new numberNode();
currentNode.setleft(newRightNode);
if (i == lengthOfCode)
{
currentNode.setright(n);
}
else
{
currentNode = newRightNode;
}
}
else
{
if (i == lengthOfCode)
{
currentNode.setright(n);
}
currentNode = currentNode.getright();
}
}
}
}
}
Couple questions I have...
Is my algorithm at least correct?
Is there an alternate way of doing this without it being so ugly?
If you need to see any more of my code please don't hesitate to ask. Thanks for your time, I truly appreciate it!
EDIT: Currently runs, but when I try to print out the output using...
for (numberNode n : nodeArray)
{
System.out.println(n.getletter());
System.out.println(n.getleft().getletter().toString()); //error here
System.out.println(n.getright().getletter());
System.out.println("");
}
I get an error where indicated,Any ideas on what's going wrong?
First, when you try to print the values out, what did the compiler say was the error on System.out.println(n.getleft().getletter().toString()); //error here?
Is each letter suppose to be the root of it's own tree? If it is suppose to be on tree, I would have a reference pointer at the start that would contain references to every letter in the alphabet, while the nodes branching off each letter would have the particular sequence that represents the Morse code for that letter. But if I was free to do whatever, I would simply create an array of 26 characters that contain a MorseCode object that has two fields, one containing the Letter and the other containing the Morse Code that is associated with that letter.
It would be helpful to understand what the output is suppose to be for this program and clarify what is in the file you are reading into the arrayList. What does that data look like?
It's basically just an implementation of the Huffman Coding algorithm, but when I check the probability of the end BinaryTree (the only item in the queue left) it's grossly high.
// Make a BinaryTree for each item in CharOccurrences and add as an entry in initialQueue
for (int i = 0; i < charOccurrences.size(); i++) {
BinaryTree<CharProfile> bTree = new BinaryTree<CharProfile>();
bTree.makeRoot(charOccurrences.get(i));
initialQueue.add(bTree);
}
// Create the BinaryTree that we're adding to the resultQueue
BinaryTree<CharProfile> treeMerge = new BinaryTree<CharProfile>();
// Create the CharProfile that will hold the probability of the two merged trees
CharProfile data;
while (!initialQueue.isEmpty()) {
// Check if the resultQueue is empty, in which case we only need to look at initialQueue
if (resultQueue.isEmpty()) {
treeMerge.setLeft(initialQueue.remove());
treeMerge.setRight(initialQueue.remove());
// Set treeMerge's data to be the sum of its two child trees' probabilities with a null char value
data = new CharProfile('\0');
data.setProbability(treeMerge.getLeft().getData().getProbability() + treeMerge.getRight().getData().getProbability());
treeMerge.setData(data);
}
else {
// Set the left part of treeMerge to the lowest of the front of the two queues
if (initialQueue.peek().getData().getProbability() <= resultQueue.peek().getData().getProbability()) {
treeMerge.setLeft(initialQueue.remove());
}
else {
treeMerge.setLeft(resultQueue.remove());
}
if (!initialQueue.isEmpty()) {
// Set the right part of treeMerge to the lowest of the front of the two queues
if (initialQueue.peek().getData().getProbability() <= resultQueue.peek().getData().getProbability()) {
treeMerge.setRight(initialQueue.remove());
}
else {
treeMerge.setRight(resultQueue.remove());
}
}
// In the case that initialQueue is now empty (as a result of just dequeuing the last element), simply make the right tree resultQueue's head
else {
treeMerge.setRight(resultQueue.remove());
}
// Set treeMerge's data to be the sum of its two child trees' probabilities with a null char value
data = new CharProfile('\0');
data.setProbability(treeMerge.getLeft().getData().getProbability() + treeMerge.getRight().getData().getProbability());
treeMerge.setData(data);
}
// Add the new tree we create to the resultQueue
resultQueue.add(treeMerge);
}
if (resultQueue.size() > 1) {
while (resultQueue.size() != 1) {
treeMerge.setLeft(resultQueue.remove());
treeMerge.setRight(resultQueue.remove());
data = new CharProfile('\0');
data.setProbability(treeMerge.getLeft().getData().getProbability() + treeMerge.getRight().getData().getProbability());
treeMerge.setData(data);
resultQueue.add(treeMerge);
}
}
I then have this at the end:
System.out.println("\nProbability of end tree: "
+ resultQueue.peek().getData().getProbability());
Which gives me:
Probability of end tree: 42728.31718061674
Move the following lines inside the while loop:
// Create the BinaryTree that we're adding to the resultQueue
BinaryTree<CharProfile> treeMerge = new BinaryTree<CharProfile>();
Otherwise, one iteration adds treeMerge to resultQueue, and the next one may do treeMerge.setLeft(resultQueue.remove());, which makes treeMerge a child of itself...
My Huffman tree which I had asked about earlier has another problem! Here is the code:
package huffman;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Scanner;
public class Huffman {
public ArrayList<Frequency> fileReader(String file)
{
ArrayList<Frequency> al = new ArrayList<Frequency>();
Scanner s;
try {
s = new Scanner(new FileReader(file)).useDelimiter("");
while (s.hasNext())
{
boolean found = false;
int i = 0;
String temp = s.next();
while(!found)
{
if(al.size() == i && !found)
{
found = true;
al.add(new Frequency(temp, 1));
}
else if(temp.equals(al.get(i).getString()))
{
int tempNum = al.get(i).getFreq() + 1;
al.get(i).setFreq(tempNum);
found = true;
}
i++;
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return al;
}
public Frequency buildTree(ArrayList<Frequency> al)
{
Frequency r = al.get(1);
PriorityQueue<Frequency> pq = new PriorityQueue<Frequency>();
for(int i = 0; i < al.size(); i++)
{
pq.add(al.get(i));
}
/*while(pq.size() > 0)
{
System.out.println(pq.remove().getString());
}*/
for(int i = 0; i < al.size() - 1; i++)
{
Frequency p = pq.remove();
Frequency q = pq.remove();
int temp = p.getFreq() + q.getFreq();
r = new Frequency(null, temp);
r.left = p;
r.right = q;
pq.add(r); // put in the correct place in the priority queue
}
pq.remove(); // leave the priority queue empty
return(r); // this is the root of the tree built
}
public void inOrder(Frequency top)
{
if(top == null)
{
return;
}
else
{
inOrder(top.left);
System.out.print(top.getString() +", ");
inOrder(top.right);
return;
}
}
public void printFreq(ArrayList<Frequency> al)
{
for(int i = 0; i < al.size(); i++)
{
System.out.println(al.get(i).getString() + "; " + al.get(i).getFreq());
}
}
}
What needs to be done now is I need to create a method that will search through the tree to find the binary code (011001 etc) to the specific character. What is the best way to do this? I thought maybe I would do a normal search through the tree as if it were an AVL tree going to the right if its bigger or left if it's smaller.
But because the nodes don't use ints doubles etc. but only using objects that contain characters as strings or null to signify its not a leaf but only a root. The other option would be to do an in-order run through to find the leaf that I'm looking for but at the same time how would I determine if I went right so many times or left so many times to get the character.
package huffman;
public class Frequency implements Comparable {
private String s;
private int n;
public Frequency left;
public Frequency right;
Frequency(String s, int n)
{
this.s = s;
this.n = n;
}
public String getString()
{
return s;
}
public int getFreq()
{
return n;
}
public void setFreq(int n)
{
this.n = n;
}
#Override
public int compareTo(Object arg0) {
Frequency other = (Frequency)arg0;
return n < other.n ? -1 : (n == other.n ? 0 : 1);
}
}
What I'm trying to do is find the binary code to actually get to each character. So if I were trying to encode aabbbcccc how would I create a string holding the binary code for a going left is 0 and going right is 1.
What has me confused is because you can't determine where anything is because the tree is obviously unbalanced and there is no determining if a character is right or left of where you are. So you have to search through the whole tree but if you get to a node that isn't what you are looking for, you have backtrack to another root to get to the other leaves.
Traverse through the huffman tree nodes to get a map like {'a': "1001", 'b': "10001"} etc. You can use this map to get the binary code to a specific character.
If you need to do in reverse, just handle it as a state machine:
state = huffman_root
for each bit
if (state.type == 'leaf')
output(state.data);
state = huffman_root
state = state.leaves[bit]
Honestly said, I didn't look into your code. It ought be pretty obvious what to do with the fancy tree.
Remember, if you have 1001, you will never have a 10010 or 10011. So your basic method looks like this (in pseudocode):
if(input == thisNode.key) return thisNode.value
if(input.endsWith(1)) return search(thisNode.left)
else return search(thisNode.right)
I didn't read your program to figure out how to integrate it, but that's a key element of huffman encoding in a nutshell
Try something like this - you're trying to find token. So if you wanted to find the String for "10010", you'd do search(root,"10010")
String search(Frequency top, String token) {
return search(top,token,0);
}
// depending on your tree, you may have to switch top.left and top.right
String search(Frequency top, String token, int depth) {
if(token.length() == depth) return "NOT FOUND";
if(token.length() == depth - 1) return top.getString();
if(token.charAt(depth) == '0') return search(top.left,token,depth+1);
else return search(top.right,token,depth+1);
}
I considered two options when I was having a go at Huffman coding encoding tree.
option 1: use pointer based binary tree. I coded most of this and then felt that, to trace up the tree from the leaf to find an encoding, I needed parent pointers. other wise, like mentioned in this post, you do a search of the tree which is not a solution to finding the encoding straight away. The disadvantage of the pointer based tree is that, I have to have 3 pointers for every node in the tree which I thought was too much. The code to follow the pointers is simple but more complicated that in option 2.
option 2: use an array based tree to represent the encoding tree that you will use on the run to encode and decode. so if you want the encoding of a character, you find the character in the array. Pretty straight forward, I use a table so smack right and there I get the leaf. now I trace up to the root which is at index 1 in the array. I do a (current_index / 2) for the parent. if child index is parent /2 it is a left and otherwise right.
option 2 was pretty easy to code up and although the array can have a empty spaces. I thought it was better in performance than a pointer based tree. Besides identifying the root and leaf now is a matter of indices rather than object type. ;) This will also be very usefull if you have to send your tree!?
also, you dont search (root, 10110) while decoding the Huffman code. You just walk the tree through the stream of encoded bitstream, take a left or right based on your bit and when you reach the leaf, you output the character.
Hope this was helpful.
Harisankar Krishna Swamy (example)
I guess your homework is either done or very late by now, but maybe this will help someone else.
It's actually pretty simple. You create a tree where 0 goes right and 1 goes left. Reading the stream will navigate you through the tree. When you hit a leaf, you found a letter and start over from the beginning. Like glowcoder said, you will never have a letter on a non-leaf node. The tree also covers every possible sequence of bits. So navigating in this way always works no matter the encoded input.
I had an assignment to write an huffman encoder/decoder just like you a while ago and I wrote a blog post with the code in Java and a longer explanation : http://www.byteauthor.com/2010/09/huffman-coding-in-java/
PS. Most of the explanation is on serializing the huffman tree with the least possible number of bits but the encoding/decoding algorithms are pretty straightforward in the sources.
Here's a Scala implementation: http://blog.flotsam.nl/2011/10/huffman-coding-done-in-scala.html