Phyks (Lucas Verney) 780e865870 Fix JavaDoc errors
2018-12-07 08:59:15 +01:00

141 lines
3.0 KiB
Java

package btools.mapsplitter;
import java.util.Comparator;
import java.util.HashMap;
import java.util.PriorityQueue;
/**
* Encoder for a set of tags
*
* It detects identical sets and sorts them
* into a huffman-tree according to their frequencies
*
* Adapted for 3-pass encoding (counters -> statistics -> encoding )
* but doesn't do anything at pass1
*/
public abstract class HuffmanTreeEncoder<V>
{
private HashMap<TreeNode, TreeNode> identityMap;
protected BitWriteBuffer bwb;
protected int pass;
private TreeNode freq1;
public void encode( V data )
{
if ( pass == 1 )
{
return;
}
TreeNode probe = new TreeNode();
probe.data = data;
TreeNode tn = identityMap.get( probe );
if ( pass == 3 )
{
if ( tn.frequency == 1 )
{
bwb.encodeBounded( freq1.range - 1, freq1.code );
encodeItem( data );
}
else
{
bwb.encodeBounded( tn.range - 1, tn.code );
}
}
else if ( pass == 2 )
{
if ( tn == null )
{
tn = probe;
identityMap.put( tn, tn );
}
tn.frequency++;
}
}
public void encodeDictionary( BitWriteBuffer bwb )
{
this.bwb = bwb;
if ( ++pass == 3 )
{
freq1 = new TreeNode();
PriorityQueue<TreeNode> queue = new PriorityQueue<TreeNode>(2*identityMap.size(), new Comparator<TreeNode>()
{
@Override
public int compare(TreeNode tn1, TreeNode tn2)
{
if ( tn1.frequency < tn2.frequency )
return -1;
if ( tn1.frequency > tn2.frequency )
return 1;
return 0;
}
} );
queue.add( freq1 );
while (queue.size() > 1)
{
TreeNode node = new TreeNode();
node.child1 = queue.poll();
node.child2 = queue.poll();
node.frequency = node.child1.frequency + node.child2.frequency;
queue.add( node );
}
TreeNode root = queue.poll();
root.encode( 1, 0 );
}
}
public HuffmanTreeEncoder()
{
identityMap = new HashMap<TreeNode, TreeNode>();
}
protected abstract void encodeItem( V data );
protected abstract boolean itemEquals( V i1, V i2 );
protected abstract int itemHashCode( V i);
public final class TreeNode
{
public V data;
public int frequency;
public int code;
public int range;
public TreeNode child1;
public TreeNode child2;
public void encode( int range, int code )
{
this.range = range;
this.code = code;
boolean isNode = child1 != null;
bwb.encodeBit( isNode );
if ( isNode )
{
child1.encode( range << 1, code );
child2.encode( range << 1, code + range );
}
else
{
bwb.encodeBit( data == null );
if ( data != null )
{
encodeItem( data );
}
}
}
@Override
public boolean equals( Object o )
{
return itemEquals( ((TreeNode)o).data, data );
}
@Override
public int hashCode()
{
return itemHashCode( data );
}
}
}