package com.e2u.tree;
import java.util.ArrayList;
import java.util.List;
import com.e2u.bit.BitUtil;
import com.e2u.util.Heap;
public class HuffmanTree
{
//The huffman tree root node
private HuffmanNode root = null;
//The byte encode table, which contains the codes of byte 0-255
private String[] encodeTable = null;
/**
* Default
*/
public HuffmanTree()
{
encodeTable = new String[256];
}
public HuffmanTree(int[] weights)
{
if(weights == null)
{
throw new NullPointerException("weights is null");
}
if(weights.length < 256)
{
throw new IllegalArgumentException("The weights length is less than " + 256);
}
encodeTable = new String[256];
byte[] elements = new byte[256];
for(int i = 0; i < 256; i++)
{
elements[i] = (byte)i;
}
buildTree(elements, weights);
}
public void buildTree(byte[] elements, int weights[])
{
if(elements == null || weights == null)
{
throw new NullPointerException("elements or weights can't be null");
}
List<HuffmanNode> leafNodeList = new ArrayList<HuffmanNode>(elements.length);
for(int i = 0; i < elements.length; i++)
{
leafNodeList.add(new HuffmanNode(elements[i], weights[i]));
}
buildTree(leafNodeList);
}
public void buildTree(List<HuffmanNode> initialNodeList)
{
Heap<HuffmanNode> hp = new Heap<HuffmanNode>(initialNodeList);
HuffmanNode lc = null, rc = null, parent = null;
while(hp.size() > 1)
{
lc = hp.remove();
rc = hp.remove();
parent = new HuffmanNode(lc.weight + rc.weight);
parent.lchild = lc;
parent.rchild = rc;
lc.parent = parent;
rc.parent = parent;
hp.insert(parent);
}
root = hp.remove();
updateEncodeMap();
}
public String getPath(HuffmanNode node)
{
if(node == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
while(node.parent != null)
{
if(node.parent.lchild == node)
{
sb.append('0');
}
else
{
sb.append('1');
}
node = node.parent;
}
return sb.reverse().toString();
}
public HuffmanNode getRoot()
{
return root;
}
public String[] getEncodeTable()
{
return encodeTable;
}
private void updateEncodeMap()
{
updateEncodeMap(root);
}
private void updateEncodeMap(HuffmanNode node)
{
if(node == null)
{
return;
}
if(node.lchild == null && node.rchild == null)
{
encodeTable[BitUtil.unsigned(node.element)] = getPath(node);
return;
}
updateEncodeMap(node.lchild);
updateEncodeMap(node.rchild);
}
}