/*
* JFLAP - Formal Languages and Automata Package
*
*
* Susan H. Rodger
* Computer Science Department
* Duke University
* August 27, 2009
* Copyright (c) 2002-2009
* All rights reserved.
* JFLAP is open source software. Please see the LICENSE for terms.
*
*/
package gui.tree;
import javax.swing.tree.*;
import java.util.*;
/**
* The Trees
class contains method for doing basic calculations
* with trees. Many of the operations assume that the TreeModel
* holds TreeNode
objects.
*
* @author Thomas Finley
*/
public class Trees {
/**
* We don't need no stinkin' instances!
*/
private Trees() {
}
/**
* Returns an array containing the children of a treenode.
*
* @param node
* the treenode to return the children for
* @return an array containing the children in the order retrieved from the
* enumerator, or an empty array if this is a leaf not
*/
public static TreeNode[] children(TreeNode node) {
TreeNode[] children = new TreeNode[node.getChildCount()];
if (!node.isLeaf()) {
int i = 0;
Enumeration enumer = node.children();
while (i < children.length)
children[i++] = (TreeNode) enumer.nextElement();
}
return children;
}
/**
* Exhaustively calculates the "widths" of levels of the tree. The width of
* the level is defined as the number of nodes with that particular depth.
*
* @return the widths of the tree, where the array returned is of length
* depth()+1
, and index 0 is always 1 (since only
* the root can be at level 0).
*/
public static int[] width(TreeModel tree) {
int[] width = new int[depth(tree) + 1];
Arrays.fill(width, 0);
Trees.width((TreeNode) tree.getRoot(), 0, width);
return width;
}
/**
* Helper function for width. This visits each node, and for its depth adds
* one to its depth field.
*
* @param node
* the node that we are currently visiting
* @param depth
* the current depth of the node
* @param array
* the width array being filled
*/
private static void width(TreeNode node, int depth, int[] array) {
array[depth++]++;
if (node.isLeaf())
return;
TreeNode[] children = Trees.children(node);
for (int i = 0; i < children.length; i++)
width(children[i], depth, array);
}
/**
* Exhaustively calculates the depth of the tree.
*
* @param tree
* the tree to get the depth of
* @return the maximum distance from a leaf to the root
*/
public static int depth(TreeModel tree) {
return depth((TreeNode) tree.getRoot());
}
/**
* Returns the depth of a subtree rooted at the indicated node.
*
* @param node
* a node in the tree
* @return the depth of the subtree rooted at this node, e.g. 0 if this node
* is a left
*/
public static int depth(TreeNode node) {
TreeNode[] children = Trees.children(node);
int max = -1;
for (int i = 0; i < children.length; i++)
max = Math.max(max, depth(children[i]));
return max + 1;
}
/**
* Returns an array containing all the leaves of a tree.
*
* @param tree
* the tree to get leaves of
* @return an array with the leaves of the tree
*/
public static TreeNode[] leaves(TreeModel tree) {
return leaves((TreeNode) tree.getRoot());
}
/**
* Returns an array containing all the leaves of a subtree rooted at the
* indicated node.
*
* @param node
* the node in the tree
* @return an array of all children in the tree
*/
public static TreeNode[] leaves(TreeNode node) {
TreeNode[] children = Trees.children(node);
if (children.length == 0)
return new TreeNode[] { node };
ArrayList leaves = new ArrayList();
for (int i = 0; i < children.length; i++) {
TreeNode[] subleaves = leaves(children[i]);
for (int j = 0; j < subleaves.length; j++)
leaves.add(subleaves[j]);
}
return (TreeNode[]) leaves.toArray(new TreeNode[0]);
}
}