View Javadoc
1   /*
2    * $Source$
3    * $Revision$
4    *
5    * Copyright (C) 2001 Myles Chippendale
6    * 
7    * Part of Melati (http://melati.org), a framework for the rapid
8    * development of clean, maintainable web applications.
9    *
10   * Melati is free software; Permission is granted to copy, distribute
11   * and/or modify this software under the terms either:
12   *
13   * a) the GNU General Public License as published by the Free Software
14   *    Foundation; either version 2 of the License, or (at your option)
15   *    any later version,
16   *
17   *    or
18   *
19   * b) any version of the Melati Software License, as published
20   *    at http://melati.org
21   *
22   * You should have received a copy of the GNU General Public License and
23   * the Melati Software License along with this program;
24   * if not, write to the Free Software Foundation, Inc.,
25   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26   * GNU General Public License and visit http://melati.org to obtain the
27   * Melati Software License.
28   *
29   * Feel free to contact the Developers of Melati (http://melati.org),
30   * if you would like to work out a different arrangement than the options
31   * outlined here.  It is our intention to allow Melati to be used by as
32   * wide an audience as possible.
33   *
34   * This program is distributed in the hope that it will be useful,
35   * but WITHOUT ANY WARRANTY; without even the implied warranty of
36   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37   * GNU General Public License for more details.
38   *
39   * Contact details for copyright holder:
40   *
41   *     Myles Chippendale <mylesc At paneris.org>
42   */
43  
44  package org.melati.util;
45  
46  import java.util.Vector;
47  
48  import org.melati.poem.util.Order;
49  import org.melati.poem.util.SortUtils;
50  import org.melati.poem.Treeable;
51  
52  /**
53   * A whole tree.
54   */
55  public class Tree {
56    private Treeable[] orig_roots;
57    private TreeNode[] roots;
58    private int depth;
59  
60    /**
61     * Constructor from root node.
62     * @param node root node
63     */
64    public Tree(Treeable node) {
65      orig_roots = new Treeable[1];
66      orig_roots[0] = node;
67      this.depth = 0;
68      roots = new TreeNode[] { new TreeNode(node, 0) };
69    }
70  
71    /**
72     * Constructor from root node with anticipated depth.
73     * @param node root node
74     * @param depth the anticipated depth
75     */
76    public Tree(Treeable node, int depth) {
77      orig_roots = new Treeable[1];
78      orig_roots[0] = node;
79      this.depth = depth;
80      roots = new TreeNode[] { new TreeNode(node, depth) };
81    }
82  
83    /**
84     * Constructor for a multi-rooted tree.
85     * @param nodes the root nodes
86     */
87    public Tree(Treeable[] nodes) {
88      orig_roots = nodes;
89      this.depth = 0;
90      roots = TreeNode.augment(nodes, 0);
91    }
92  
93    /**
94     * Constructor for a multi-rooted tree with anticipated depth.
95     * @param nodes the root nodes
96     * @param depth anticipated depth
97     */
98    public Tree(Treeable[] nodes, int depth) {
99      orig_roots = nodes;
100     this.depth = depth;
101     roots = TreeNode.augment(nodes, depth);
102   }
103 
104   /**
105    * @return the roots
106    */
107   public Treeable[] getTreeableRoots() {
108     return orig_roots;
109   }
110 
111   /**
112    * @return the depth, possibly anticipated
113    */
114   public int getDepth() {
115     return depth;
116   }
117 
118   /**
119    * Retrieve all the nodes down to a given depth.
120    * @param depthP
121    *        Only apply the function to nodes at or above this depth. A negative
122    *        depth means apply this to all nodes in the tree
123    * @param depthFirst
124    *        If true, traverse the tree depth-first, otherwise traverse it
125    *        breadth-first
126    * @return all the nodes down to the given depth
127    */
128   public Vector<TreeNode> flattened(int depthP, boolean depthFirst) {
129 
130     Vector<TreeNode> results = new Vector<TreeNode>();
131     Vector<TreeNode> agenda = new Vector<TreeNode>();
132     for (int i = 0; i < roots.length; i++) {
133       agenda.addElement(roots[i]);
134     }
135 
136     while (!agenda.isEmpty()) {
137       TreeNode current = (TreeNode)agenda.firstElement();
138       agenda.removeElementAt(0);
139       results.addElement(current);
140 
141       if (depthP < 0 || current.depth < depthP) {
142         TreeNode[] kids = current.getChildren();
143 
144         if (kids != null) {
145           for (int i = 0; i < kids.length; i++) {
146             if (depthFirst)
147               // Maybe not the most efficient ...?
148               agenda.insertElementAt(kids[i], i);
149             else
150               agenda.addElement(kids[i]);
151           }
152         }
153       }
154     }
155     return results;
156   }
157 
158   /**
159    * Retrieve all the nodes down to a given depth, depth-first.
160    * @param depthP
161    *        Only apply the function to nodes at or above this depth. A negative
162    *        depth means apply this to all nodes in the tree
163    * @return all the nodes down to the given depth
164    */
165   public Vector<TreeNode> flattened(int depthP) {
166     return flattened(depthP, true);
167   }
168 
169   /**
170    * @return all the nodes, depth-first
171    */
172   public Vector<TreeNode> flattened() {
173     return flattened(-1);
174   }
175 
176   /**
177    * Apply the Function to each node in the tree.
178    * 
179    * @param func the Function to apply
180    * @param depthP
181    *        Only apply the function to nodes at or above this depth. A negative
182    *        depth means apply this to all nodes in the tree
183    * @param depthFirst
184    *        If true, traverse the tree depth-first, otherwise traverse it
185    *        breadth-first
186    * @return a Vector nodes that have had func applied to them
187    */
188   public Vector<TreeNode> apply(Function func, int depthP, boolean depthFirst) {
189     Vector<TreeNode> flattened = flattened(depthP, depthFirst);
190     for (int i = 0; i < flattened.size(); i++) {
191       flattened.setElementAt((TreeNode)func.apply(flattened.elementAt(i)), i);
192     }
193     return flattened;
194   }
195 
196   /**
197    * Apply a function to all nodes, depth first.
198    * @param func the function to apply
199    * @return a vector of nodes to which the function has been applied
200    */
201   public Vector<TreeNode> applyDepthFirst(Function func) {
202     return apply(func, -1, true);
203   }
204 
205   /**
206    * Apply a function to all nodes to a given depth, depth first.
207    * @param func the function to apply
208    * @param depthP
209    *        Only apply the function to nodes at or above this depth. A negative
210    *        depth means apply this to all nodes in the tree
211    * @return a vector of nodes to which the function has been applied
212    */
213   public Vector<TreeNode> applyDepthFirst(Function func, int depthP) {
214     return apply(func, depthP, true);
215   }
216 
217   /**
218    * Apply a function to all nodes, breadth first.
219    * @param func the function to apply
220    * @return a vector of nodes to which the function has been applied
221    */
222   public Vector<TreeNode> applyBreadthFirst(Function func) {
223     return apply(func, -1, false);
224   }
225 
226   /**
227    * Apply a function to all nodes to a given depth, breadth first.
228    * @param func the function to apply
229    * @param depthP
230    *        Only apply the function to nodes at or above this depth. A negative
231    *        depth means apply this to all nodes in the tree
232    * @return a vector of nodes to which the function has been applied
233    */
234   public Vector<TreeNode> applyBreadthFirst(Function func, int depthP) {
235     return apply(func, depthP, false);
236   }
237 
238   /**
239    * Retrieve a sorted Vector of the tree's contents, down to the given depth. 
240    * @param cmp an Ordering
241    * @param depthP
242    *        Only return nodes at or above this depth. A negative
243    *        depth means return all nodes in the tree
244    * @return a sorted Vector of the tree's contents, down to the given depth
245    */
246   public Vector<TreeNode> sorted(Order cmp, int depthP) {
247     Vector<TreeNode> flattened = flattened(depthP);
248     TreeNode[] sorted = SortUtils.sorted(cmp, flattened);
249     System.arraycopy(sorted, 0, flattened, 0, sorted.length);
250     return flattened;
251   }
252 
253 }