Closed GoogleCodeExporter closed 9 years ago
Maybe it would be useful to have a Tree interface
Tree<T> {
T getParent();
Collection<T> getChildren();
}
also see issue 187
Original comment by zeitlin...@gmail.com
on 10 Jun 2009 at 7:46
Tree's are inherently recursive by definition. Each child of a node a Tree
itself,
with or without children nodes. As a result, the above interface wouldn't
really be
expressive enough (especially as the "key" value for the is not considered).
The next point to consider is that tree traversal can consist of pre-order,
in-order
and post-order traversals, not to mention breadth-first.
Original comment by gpampara@gmail.com
on 22 Jul 2009 at 4:02
I have always very much wanted to have a standard TreeNode<T> interface. I will
give
it more thought when I can. I think that is a far better approach than the
Function-
based one.
The interface _might_ end up needing to be something like this
interface TreeNode<T extends TreeNode<T, C>, C extends Iterable<T>> {
// optional; returns null if root
TreeNode<T, C> parent();
C children();
}
This way, different types of trees can use different types of collections
(list, set,
multiset, what-have-you). It's a little confusing to grasp at first though.
We'll
see what shakes out.
Original comment by kevin...@gmail.com
on 17 Sep 2009 at 5:41
Original comment by kevin...@gmail.com
on 17 Sep 2009 at 5:45
Original comment by kevin...@gmail.com
on 17 Sep 2009 at 5:57
You don't really need a defined data structure to implement the most common
traversals (breadth, pre/post-
order, and full depth-first - tracking start/finish times), as the original
poster points out. I would implement
it differently (see below), but the principle holds.
That's not to say there isn't a good use case for a tree data structure, just
that those traversals don't require
it. If adding both things, it would be a good idea for some static utils
methods that simplify the common use
case when you do want to traverse an explicit tree structure instead of the
functional way. There's no reason
the API can't be expressive enough for both strategies.
Additionally, if going down that data structure road, you may seriously want to
consider keeping it consistent
with the Collections model of data structures being containers for
user-supplied objects. In that light, I think
TreeNode is inappropriate for the same reason that ListNode would be. You don't
ask the elements of a List
for previous/next elements, you ask the List data structure itself.
One drawback to this is that it can be very difficult to maintain the invariant
of being a Tree while building
one. My mutable structures tend to be either general graphs or forests, with an
ability to get tree views (tree
rooted at a given forest node, e.g.).
As an aside, I'm in the process of a complete overhaul of my own graph library,
having been inspired by your
excellent work with GCL - in particular the realization of how much readability
can improve an API (and
having written it pre-generics). This is a working concept for how traversals
would look (not compilable,
poorly formatted, no method bodies - keeping it terse). For everyone out there,
feel free to use any ideas you
like.
public interface Step< E >
{
E from();
E to();
}
public interface PruningIterator< E > extends Iterator< E >
{
// Don't explore beyond the last object returned by next()
public void prune();
}
public class Steps
{
// convenience methods, so users don't have to explicitly create Steps
public static Iterator< Step< E > > wrap
( E from,
Iterator< E > toIterator )
public static Function< E, Iterator< Step< E > > > wrap
( Function< E, Iterator< E > > adjacencyFunction )
}
public class Traversals
{
public static PruningIterator< Step< E > > preOrder
( E start,
Function< E, Iterator< Step< E > > > adjacencyFunction )
// can't prune() a post-order traversal
public static Iterator< Step< E > > postOrder
( E start,
Function< E, Iterator< Step< E > > > adjacencyFunction )
public static Iterator< Step< E > > topologicalSort
( Iterator< E > nodeIterator,
Function< E, Iterator< Step< E > > > adjacencyFunction )
// etc. plus similar methods taking just Function< E, Iterator< E > > and doing the wrapping for you.
}
All of these can be implemented using stacks, no recursion, without too much
difficulty. The primary reason
for the Step interface is that you often want to know from which node you
traversed, and this information
would not otherwise be available.
I can use this same API to traverse the file system, up a tree instead of down,
or any other graph-like
structure, without creating an explicit data structure to do it. All I need to
define is that function which takes
a node and returns an iterator of adjacent nodes. Not creating an actual data
structure (like a Collection) is
useful when the backing data is huge, and perhaps not even queryable in a
global way. Having to implement
things like size() can really be a pain sometimes, and at work we've often just
decided to throw an
UnsupportedOperationException instead.
At any rate, a work in progress, but that's the general flavor. The edges in my
data structures also contain
user-defined objects, so I need to allow for that without polluting the rest of
the API. Still working through
the implications of that.
Original comment by ray.a.co...@gmail.com
on 2 Oct 2009 at 11:35
I recently needed a version of my walk iterable from above with a possibility
to get
the path of a node to the root. So I needed a TreeNode interface, without
needing the
children (although it could easily be added).
I'm attaching the relevant bits (thrown together so it would compile, but i did
not
spend too much time on it so please excuse for errors). Scroll down for an
example in
printWalkWithParentsTest()
Original comment by jvdne...@gmail.com
on 10 Dec 2009 at 5:34
Attachments:
This issue has been moved to the Guava project (keeping the same id number).
Simply replace 'google-collections' with 'guava-libraries' in your address
bar and it should take you there.
Original comment by kevinb@google.com
on 5 Jan 2010 at 11:09
Original issue reported on code.google.com by
jvdne...@gmail.com
on 25 May 2009 at 2:34