I started looking into various approaches of storing trees first. If it is a case of tree with multiple children, but only single parent, then we can choose to use nested set model. A comprehensive description in mysql is discussed here. I have personally implemented it and works well.
But, if you want to model a DAG kind of structure with multiple parents, then it gets difficult. A good article on this can be found here. It discusses about various operations on nodes and links. Operations like delete link gets pretty complicated.
So, I thought may be a in memory implementation would be a better alternative. I went ahead and wrote a inmemory thread implementation using DFS, which gives all the parents in the path till given node(maybe through multiple paths), and all the children in subtree on a given node.
Here is a brief outline of it :
//datastructure to store childrens and parents
public class Node {
HashSet<Long> childrens = new HashSet<Long>();
HashSet<Long> parents = new HashSet<Long>(); //parents in path
public HashSet<Long> getChildrens() {
return childrens;
}
public void setChildrens(HashSet<Long> childrens) {
this.childrens = childrens;
}
public HashSet<Long> getParents() {
return parents;
}
public void setParents(HashSet<Long> parents) {
this.parents = parents;
}
}
//adjacency list (Node id, neighbour id list)
private HashMap<Long,List<Long>> adjList= new HashMap<Long, List<Long>>();
//all the nodes hashed on node id
private HashMap<Long,Node> data = new HashMap<Long, Node>();
public void init() {
//find nodes which have no inlink from adjacency list
HashSet<Long> parents = new HashSet<Long>(); //who are roots
for(Long k : data.keySet()) {
//add dummy nodes in adjacency list for nodes having no links
if(!adjList.containsKey(k)) {
adjList.put(k,new ArrayList<Long>());
}
boolean found = false;
for(Long p : adjList.keySet()) {
if(adjList.get(p).contains(k)) {
found=true; break;
}
}
if(!found) parents.add(k);
}
//start dfs
HashSet<Long> parentNull = new HashSet<Long>();
for(Long u : parents) {
dfs(u,parentNull);
}
}
/**
* @param node
* current node
* @param parents
* set of all parents of given node
* @return all subtree nodes as children
*/
HashSet<Long> dfs(Long node, HashSet<Long> parents) {
//cycle exists
if(parents.contains(node)) {
throw new Exception("Contains cycle");
}
//add parents to current node
data.get(node).getParents().addAll(parents);
//construct new set of parent for passing to children
HashSet<Long> newParent = new HashSet<Long>(data.get(node).getParents());
newParent.add(node);
//do a dfs to all its children
for(Long neighbours : adjList.get(node)) {
HashSet<Long> childrens = dfs(neighbours,newParent);
data.get(node).getChildrens().addAll(childrens);
}
//it has subtree..so return all children
if(adjList.get(node).size()>0) {
return data.get(node).getChildrens();
}
else {
//add only current node
HashSet<Long> ret = new HashSet<Long>();
ret.add(node);
return ret;
}
}
No comments:
Post a Comment