import jdsl.core.algo.traversals.*;
import jdsl.core.api.*;
import jdsl.core.ref.*;
import java.util.Random;
/**
* Class that builds a random tree. Each node stores a random
* name from a Sequence of names.
*
* @author Lucy Perry (lep)
* @version JDSL 2
*/
public class RandomTreeBuilder {
/* ************************************ */
/* The members described in the lesson. */
/* ************************************ */
//b6.1
protected Tree tree;
protected Sequence names;
//e6.1
/**
*Builds a random tree. The build method does the work.
*/
//b6.2
public Tree randomTree(int n) {
// Create a random binary tree with n external nodes
tree = new NodeTree();
names = NameGenerator.getNames();
build(tree.root(), n); // auxiliary recursive method
return tree;
}
//e6.2
/**
* Recursively build a random tree. The algorithm builds a subtree with
* n nodes with root node p as follows:
* - If n=1 then do nothing
* - Otherwise
* - randomly select the size of the subtree rooted at the first child
* - repeat until the number of nodes to build has been distributed to
* children subtrees.
* - randomly permute the order of sizes.
* - recursively build each subtree
*/
//b6.3
protected void build(Position p, int n) {
int toBuild = n-1;
Sequence sizes=new ArraySequence();
if (tree.isExternal(p)) {
while (toBuild>0) {
int size = randomInteger(1, toBuild);
sizes.insertLast(new Integer(size));
toBuild-=size;
}
permute(sizes);
for(int i=0; i<sizes.size();i++){
Position pos = tree.insertLastChild(p,null);
int size = ((Integer)sizes.atRank(i).element()).intValue();
build(pos,size);
}
tree.replaceElement(p,pickName());
}
}
//e6.3
/* ************************************ */
/* Members not described in the lesson. */
/* ************************************ */
protected Random gen = new Random();
/**
* Randomly permute a sequence. This is the same method as in lesson 2.
*/
protected void permute(Sequence s) {
for(int i=s.size()-1;i>1;i--) {
int j=randomInteger(1,i);
if (j<i)
s.swapElements(s.atRank(i),s.atRank(j));
}
}
/**
* Randomly pick a name.
*/
protected String pickName() {
int i=randomInteger(0,names.size()-1);
return (String)names.atRank(i).element();
}
/**
* Return a random integer i such that min <= i <= max
*/
protected int randomInteger(int min, int max) {
int r = gen.nextInt(max-min+1);
return r+min;
}
}