package com.e2u.alg.tree;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.swing.tree.DefaultMutableTreeNode;
import com.e2u.bit.BitUtil;
public class TreeSerialization
{
public static byte[] encode(DefaultMutableTreeNode root)
{
ByteBuffer byteBuffer = new ByteBuffer();
LinkedList<SNode> que = new LinkedList<SNode>();
SNode rootTNode = new SNode(root, 0, -1);
que.add(rootTNode);
int level = 0;
int nodeNumber = -1;
int count = 0;
SNode curNode = null;
while(!que.isEmpty())
{
curNode = que.removeFirst();
byteBuffer.add(curNode.encode());
if(curNode.level > level)
{
level = curNode.level;
nodeNumber = 0;
}
else
{
nodeNumber++;
}
//put all the children into the queue
count = curNode.node.getChildCount();
for(int i = 0; i < count; i++)
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode)curNode.node.getChildAt(i);
SNode tnode = new SNode(node, level + 1, nodeNumber);
que.add(tnode);
}
}
return byteBuffer.getData();
}
public static DefaultMutableTreeNode decode(byte[] bytes)
{
SNode snode = SNode.decode(bytes, 0);
DefaultMutableTreeNode root = snode.node;
List<List<DefaultMutableTreeNode>> nodeListList = new ArrayList<List<DefaultMutableTreeNode>>();
List<DefaultMutableTreeNode> nodeList = new ArrayList<DefaultMutableTreeNode>();
nodeListList.add(nodeList);
int curParentLevel = snode.level;
//root node
nodeList.add(snode.node);
for(int i = 12; i < bytes.length; i += 12)
{
snode = SNode.decode(bytes, i);
//The current level's storage list exist?
if(snode.level > nodeListList.size() - 1)
{
nodeList = new ArrayList<DefaultMutableTreeNode>();
nodeListList.add(nodeList);
}
nodeList.add(snode.node);
if(snode.level == curParentLevel + 2)
{
//Only the parent level and current level's list data will be used
//So the stale data can be deleted.
nodeListList.get(curParentLevel).clear();
curParentLevel++;
}
DefaultMutableTreeNode p = nodeListList.get(curParentLevel).get(snode.parentIndex);
p.add(snode.node);
}
return root;
}
private static void breadPrint(DefaultMutableTreeNode r)
{
DefaultMutableTreeNode node;
Enumeration enu = r.breadthFirstEnumeration();
while(enu.hasMoreElements())
{
node = (DefaultMutableTreeNode)enu.nextElement();
System.out.print(node.getUserObject() + " ");
}
System.out.println();
}
/**
* A simple byte array wrapper class
*/
private static class ByteBuffer
{
private int offset = 0;
private byte[] bytes = null;
public ByteBuffer()
{
bytes = new byte[1024];
offset = 0;
}
public void add(byte[] src)
{
for(int i = 0; i < src.length; i++)
{
bytes[offset++] = src[i];
}
}
public byte[] getData()
{
if(offset <= 0)
{
return new byte[0];
}
byte[] r = new byte[offset];
System.arraycopy(bytes, 0,r, 0, offset);
return r;
}
}
/**
* Serialization Node
*/
private static class SNode
{
public DefaultMutableTreeNode node;
//node's level, start from 0
public int level;
//the index of the parent
public int parentIndex;
public SNode(){}
public SNode(DefaultMutableTreeNode node, int level, int parentIndex)
{
this.node = node;
this.level = level;
this.parentIndex = parentIndex;
}
public byte[] encode()
{
byte[] bytes = new byte[12];
BitUtil.toByte(bytes, 0, level);
BitUtil.toByte(bytes, 4, parentIndex);
BitUtil.toByte(bytes, 8, (Integer)(node.getUserObject()));
return bytes;
}
public static SNode decode(byte[] bytes, int offset)
{
SNode tnode = new SNode();
tnode.level = BitUtil.constructInt(bytes, offset + 0);
tnode.parentIndex = BitUtil.constructInt(bytes, offset + 4);
DefaultMutableTreeNode node = new DefaultMutableTreeNode();
int userData = BitUtil.constructInt(bytes, offset + 8);
node.setUserObject(userData);
tnode.node = node;
return tnode;
}
}
private static DefaultMutableTreeNode buildTree()
{
Map<Integer, DefaultMutableTreeNode> map = new HashMap<Integer, DefaultMutableTreeNode>();
DefaultMutableTreeNode node;
for(int i = 0; i < 16; i++)
{
node = new DefaultMutableTreeNode(i);
map.put(i, node);
}
// 0
node = map.get(0);
node.add(map.get(1));
node.add(map.get(2));
node.add(map.get(3));
node.add(map.get(4));
// 1
node = map.get(1);
node.add(map.get(5));
node.add(map.get(6));
node.add(map.get(7));
node.add(map.get(8));
// 3
node = map.get(3);
node.add(map.get(9));
node.add(map.get(10));
node.add(map.get(11));
// 4
node = map.get(4);
node.add(map.get(12));
node.add(map.get(13));
// 7
node = map.get(7);
node.add(map.get(14));
node.add(map.get(15));
//root node
node = map.get(0);
//for gc
map.clear();
return node;
}
public static void test()
{
DefaultMutableTreeNode intputRoot = buildTree();
breadPrint(intputRoot);
byte[] bytes = TreeSerialization.encode(intputRoot);
DefaultMutableTreeNode outputRoot = TreeSerialization.decode(bytes);
breadPrint(outputRoot);
}
/**
* @param args
*/
public static void main(String[] args)
{
test();
}
}