Chris@0
|
1 # tree.rb
|
Chris@0
|
2 #
|
Chris@0
|
3 # $Revision: 1.29 $ by $Author: anupamsg $
|
Chris@0
|
4 # $Name: $
|
Chris@0
|
5 #
|
Chris@0
|
6 # = tree.rb - Generic Multi-way Tree implementation
|
Chris@0
|
7 #
|
Chris@0
|
8 # Provides a generic tree data structure with ability to
|
Chris@0
|
9 # store keyed node elements in the tree. The implementation
|
Chris@0
|
10 # mixes in the Enumerable module.
|
Chris@0
|
11 #
|
Chris@0
|
12 # Author:: Anupam Sengupta (anupamsg@gmail.com)
|
Chris@0
|
13 #
|
Chris@0
|
14
|
Chris@0
|
15 # Copyright (c) 2006, 2007 Anupam Sengupta
|
Chris@0
|
16 #
|
Chris@0
|
17 # All rights reserved.
|
Chris@0
|
18 #
|
Chris@0
|
19 # Redistribution and use in source and binary forms, with or without modification,
|
Chris@0
|
20 # are permitted provided that the following conditions are met:
|
Chris@0
|
21 #
|
Chris@0
|
22 # - Redistributions of source code must retain the above copyright notice, this
|
Chris@0
|
23 # list of conditions and the following disclaimer.
|
Chris@0
|
24 #
|
Chris@0
|
25 # - Redistributions in binary form must reproduce the above copyright notice, this
|
Chris@0
|
26 # list of conditions and the following disclaimer in the documentation and/or
|
Chris@0
|
27 # other materials provided with the distribution.
|
Chris@0
|
28 #
|
Chris@0
|
29 # - Neither the name of the organization nor the names of its contributors may
|
Chris@0
|
30 # be used to endorse or promote products derived from this software without
|
Chris@0
|
31 # specific prior written permission.
|
Chris@0
|
32 #
|
Chris@0
|
33 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
Chris@0
|
34 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
Chris@0
|
35 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
Chris@0
|
36 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
Chris@0
|
37 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
Chris@0
|
38 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
Chris@0
|
39 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
Chris@0
|
40 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
Chris@0
|
41 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
Chris@0
|
42 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
Chris@0
|
43 #
|
Chris@0
|
44
|
Chris@0
|
45 # This module provides a TreeNode class which is the primary class for all
|
Chris@0
|
46 # nodes represented in the Tree.
|
Chris@0
|
47 # This module mixes in the Enumerable module.
|
Chris@0
|
48 module Tree
|
Chris@0
|
49
|
Chris@0
|
50 # Rubytree Package Version
|
Chris@0
|
51 VERSION = '0.5.2'
|
Chris@0
|
52
|
Chris@0
|
53 # == TreeNode Class Description
|
Chris@0
|
54 #
|
Chris@0
|
55 # The node class for the tree representation. the nodes are named and have a
|
Chris@0
|
56 # place-holder for the node data (i.e., the `content' of the node). The node
|
Chris@0
|
57 # names are expected to be unique. In addition, the node provides navigation
|
Chris@0
|
58 # methods to traverse the tree.
|
Chris@0
|
59 #
|
Chris@0
|
60 # The nodes can have any number of child nodes attached to it. Note that while
|
Chris@0
|
61 # this implementation does not support directed graphs, the class itself makes
|
Chris@0
|
62 # no restrictions on associating a node's CONTENT with multiple parent nodes.
|
Chris@0
|
63 #
|
Chris@0
|
64 #
|
Chris@0
|
65 # == Example
|
Chris@0
|
66 #
|
Chris@0
|
67 # The following code-snippet implements this tree structure:
|
Chris@0
|
68 #
|
Chris@0
|
69 # +------------+
|
Chris@0
|
70 # | ROOT |
|
Chris@0
|
71 # +-----+------+
|
Chris@0
|
72 # +-------------+------------+
|
Chris@0
|
73 # | |
|
Chris@0
|
74 # +-------+-------+ +-------+-------+
|
Chris@0
|
75 # | CHILD 1 | | CHILD 2 |
|
Chris@0
|
76 # +-------+-------+ +---------------+
|
Chris@0
|
77 # |
|
Chris@0
|
78 # |
|
Chris@0
|
79 # +-------+-------+
|
Chris@0
|
80 # | GRANDCHILD 1 |
|
Chris@0
|
81 # +---------------+
|
Chris@0
|
82 #
|
Chris@0
|
83 # require 'tree'
|
Chris@0
|
84 #
|
Chris@0
|
85 # myTreeRoot = Tree::TreeNode.new("ROOT", "Root Content")
|
Chris@0
|
86 #
|
Chris@0
|
87 # myTreeRoot << Tree::TreeNode.new("CHILD1", "Child1 Content") << Tree::TreeNode.new("GRANDCHILD1", "GrandChild1 Content")
|
Chris@0
|
88 #
|
Chris@0
|
89 # myTreeRoot << Tree::TreeNode.new("CHILD2", "Child2 Content")
|
Chris@0
|
90 #
|
Chris@0
|
91 # myTreeRoot.printTree
|
Chris@0
|
92 #
|
Chris@0
|
93 # child1 = myTreeRoot["CHILD1"]
|
Chris@0
|
94 #
|
Chris@0
|
95 # grandChild1 = myTreeRoot["CHILD1"]["GRANDCHILD1"]
|
Chris@0
|
96 #
|
Chris@0
|
97 # siblingsOfChild1Array = child1.siblings
|
Chris@0
|
98 #
|
Chris@0
|
99 # immediateChildrenArray = myTreeRoot.children
|
Chris@0
|
100 #
|
Chris@0
|
101 # # Process all nodes
|
Chris@0
|
102 #
|
Chris@0
|
103 # myTreeRoot.each { |node| node.content.reverse }
|
Chris@0
|
104 #
|
Chris@0
|
105 # myTreeRoot.remove!(child1) # Remove the child
|
Chris@0
|
106 class TreeNode
|
Chris@0
|
107 include Enumerable
|
Chris@0
|
108
|
Chris@0
|
109 attr_reader :content, :name, :parent
|
Chris@0
|
110 attr_writer :content
|
Chris@0
|
111
|
Chris@0
|
112 # Constructor which expects the name of the node
|
Chris@0
|
113 #
|
Chris@0
|
114 # Name of the node is expected to be unique across the
|
Chris@0
|
115 # tree.
|
Chris@0
|
116 #
|
Chris@0
|
117 # The content can be of any type, and is defaulted to _nil_.
|
Chris@0
|
118 def initialize(name, content = nil)
|
Chris@0
|
119 raise "Node name HAS to be provided" if name == nil
|
Chris@0
|
120 @name = name
|
Chris@0
|
121 @content = content
|
Chris@0
|
122 self.setAsRoot!
|
Chris@0
|
123
|
Chris@0
|
124 @childrenHash = Hash.new
|
Chris@0
|
125 @children = []
|
Chris@0
|
126 end
|
Chris@0
|
127
|
Chris@0
|
128 # Returns a copy of this node, with the parent and children links removed.
|
Chris@0
|
129 def detached_copy
|
Chris@0
|
130 Tree::TreeNode.new(@name, @content ? @content.clone : nil)
|
Chris@0
|
131 end
|
Chris@0
|
132
|
Chris@0
|
133 # Print the string representation of this node.
|
Chris@0
|
134 def to_s
|
Chris@0
|
135 "Node Name: #{@name}" +
|
Chris@0
|
136 " Content: " + (@content || "<Empty>") +
|
Chris@0
|
137 " Parent: " + (isRoot?() ? "<None>" : @parent.name) +
|
Chris@0
|
138 " Children: #{@children.length}" +
|
Chris@0
|
139 " Total Nodes: #{size()}"
|
Chris@0
|
140 end
|
Chris@0
|
141
|
Chris@0
|
142 # Returns an array of ancestors in reversed order (the first element is the
|
Chris@0
|
143 # immediate parent). Returns nil if this is a root node.
|
Chris@0
|
144 def parentage
|
Chris@0
|
145 return nil if isRoot?
|
Chris@0
|
146
|
Chris@0
|
147 parentageArray = []
|
Chris@0
|
148 prevParent = self.parent
|
Chris@0
|
149 while (prevParent)
|
Chris@0
|
150 parentageArray << prevParent
|
Chris@0
|
151 prevParent = prevParent.parent
|
Chris@0
|
152 end
|
Chris@0
|
153
|
Chris@0
|
154 parentageArray
|
Chris@0
|
155 end
|
Chris@0
|
156
|
Chris@0
|
157 # Protected method to set the parent node.
|
Chris@0
|
158 # This method should NOT be invoked by client code.
|
Chris@0
|
159 def parent=(parent)
|
Chris@0
|
160 @parent = parent
|
Chris@0
|
161 end
|
Chris@0
|
162
|
Chris@0
|
163 # Convenience synonym for TreeNode#add method. This method allows a convenient
|
Chris@0
|
164 # method to add children hierarchies in the tree.
|
Chris@0
|
165 #
|
Chris@0
|
166 # E.g. root << child << grand_child
|
Chris@0
|
167 def <<(child)
|
Chris@0
|
168 add(child)
|
Chris@0
|
169 end
|
Chris@0
|
170
|
Chris@0
|
171 # Adds the specified child node to the receiver node. The child node's
|
Chris@0
|
172 # parent is set to be the receiver. The child is added as the last child in
|
Chris@0
|
173 # the current list of children for the receiver node.
|
Chris@0
|
174 def add(child)
|
Chris@0
|
175 raise "Child already added" if @childrenHash.has_key?(child.name)
|
Chris@0
|
176
|
Chris@0
|
177 @childrenHash[child.name] = child
|
Chris@0
|
178 @children << child
|
Chris@0
|
179 child.parent = self
|
Chris@0
|
180 return child
|
Chris@0
|
181
|
Chris@0
|
182 end
|
Chris@0
|
183
|
Chris@0
|
184 # Removes the specified child node from the receiver node. The removed
|
Chris@0
|
185 # children nodes are orphaned but available if an alternate reference
|
Chris@0
|
186 # exists.
|
Chris@0
|
187 #
|
Chris@0
|
188 # Returns the child node.
|
Chris@0
|
189 def remove!(child)
|
Chris@0
|
190 @childrenHash.delete(child.name)
|
Chris@0
|
191 @children.delete(child)
|
Chris@0
|
192 child.setAsRoot! unless child == nil
|
Chris@0
|
193 return child
|
Chris@0
|
194 end
|
Chris@0
|
195
|
Chris@0
|
196 # Removes this node from its parent. If this is the root node, then does
|
Chris@0
|
197 # nothing.
|
Chris@0
|
198 def removeFromParent!
|
Chris@0
|
199 @parent.remove!(self) unless isRoot?
|
Chris@0
|
200 end
|
Chris@0
|
201
|
Chris@0
|
202 # Removes all children from the receiver node.
|
Chris@0
|
203 def removeAll!
|
Chris@0
|
204 for child in @children
|
Chris@0
|
205 child.setAsRoot!
|
Chris@0
|
206 end
|
Chris@0
|
207 @childrenHash.clear
|
Chris@0
|
208 @children.clear
|
Chris@0
|
209 self
|
Chris@0
|
210 end
|
Chris@0
|
211
|
Chris@0
|
212 # Indicates whether this node has any associated content.
|
Chris@0
|
213 def hasContent?
|
Chris@0
|
214 @content != nil
|
Chris@0
|
215 end
|
Chris@0
|
216
|
Chris@0
|
217 # Protected method which sets this node as a root node.
|
Chris@0
|
218 def setAsRoot!
|
Chris@0
|
219 @parent = nil
|
Chris@0
|
220 end
|
Chris@0
|
221
|
Chris@0
|
222 # Indicates whether this node is a root node. Note that
|
Chris@0
|
223 # orphaned children will also be reported as root nodes.
|
Chris@0
|
224 def isRoot?
|
Chris@0
|
225 @parent == nil
|
Chris@0
|
226 end
|
Chris@0
|
227
|
Chris@0
|
228 # Indicates whether this node has any immediate child nodes.
|
Chris@0
|
229 def hasChildren?
|
Chris@0
|
230 @children.length != 0
|
Chris@0
|
231 end
|
Chris@0
|
232
|
Chris@0
|
233 # Indicates whether this node is a 'leaf' - i.e., one without
|
Chris@0
|
234 # any children
|
Chris@0
|
235 def isLeaf?
|
Chris@0
|
236 !hasChildren?
|
Chris@0
|
237 end
|
Chris@0
|
238
|
Chris@0
|
239 # Returns an array of all the immediate children. If a block is given,
|
Chris@0
|
240 # yields each child node to the block.
|
Chris@0
|
241 def children
|
Chris@0
|
242 if block_given?
|
Chris@0
|
243 @children.each {|child| yield child}
|
Chris@0
|
244 else
|
Chris@0
|
245 @children
|
Chris@0
|
246 end
|
Chris@0
|
247 end
|
Chris@0
|
248
|
Chris@0
|
249 # Returns the first child of this node. Will return nil if no children are
|
Chris@0
|
250 # present.
|
Chris@0
|
251 def firstChild
|
Chris@0
|
252 children.first
|
Chris@0
|
253 end
|
Chris@0
|
254
|
Chris@0
|
255 # Returns the last child of this node. Will return nil if no children are
|
Chris@0
|
256 # present.
|
Chris@0
|
257 def lastChild
|
Chris@0
|
258 children.last
|
Chris@0
|
259 end
|
Chris@0
|
260
|
Chris@0
|
261 # Returns every node (including the receiver node) from the tree to the
|
Chris@0
|
262 # specified block. The traversal is depth first and from left to right in
|
Chris@0
|
263 # pre-ordered sequence.
|
Chris@0
|
264 def each &block
|
Chris@0
|
265 yield self
|
Chris@0
|
266 children { |child| child.each(&block) }
|
Chris@0
|
267 end
|
Chris@0
|
268
|
Chris@0
|
269 # Traverses the tree in a pre-ordered sequence. This is equivalent to
|
Chris@0
|
270 # TreeNode#each
|
Chris@0
|
271 def preordered_each &block
|
Chris@0
|
272 each(&block)
|
Chris@0
|
273 end
|
Chris@0
|
274
|
Chris@0
|
275 # Performs breadth first traversal of the tree rooted at this node. The
|
Chris@0
|
276 # traversal in a given level is from left to right.
|
Chris@0
|
277 def breadth_each &block
|
Chris@0
|
278 node_queue = [self] # Create a queue with self as the initial entry
|
Chris@0
|
279
|
Chris@0
|
280 # Use a queue to do breadth traversal
|
Chris@0
|
281 until node_queue.empty?
|
Chris@0
|
282 node_to_traverse = node_queue.shift
|
Chris@0
|
283 yield node_to_traverse
|
Chris@0
|
284 # Enqueue the children from left to right.
|
Chris@0
|
285 node_to_traverse.children { |child| node_queue.push child }
|
Chris@0
|
286 end
|
Chris@0
|
287 end
|
Chris@0
|
288
|
Chris@0
|
289 # Yields all leaf nodes from this node to the specified block. May yield
|
Chris@0
|
290 # this node as well if this is a leaf node. Leaf traversal depth first and
|
Chris@0
|
291 # left to right.
|
Chris@0
|
292 def each_leaf &block
|
Chris@0
|
293 self.each { |node| yield(node) if node.isLeaf? }
|
Chris@0
|
294 end
|
Chris@0
|
295
|
Chris@0
|
296 # Returns the requested node from the set of immediate children.
|
Chris@0
|
297 #
|
Chris@0
|
298 # If the parameter is _numeric_, then the in-sequence array of children is
|
Chris@0
|
299 # accessed (see Tree#children). If the parameter is not _numeric_, then it
|
Chris@0
|
300 # is assumed to be the *name* of the child node to be returned.
|
Chris@0
|
301 def [](name_or_index)
|
Chris@0
|
302 raise "Name_or_index needs to be provided" if name_or_index == nil
|
Chris@0
|
303
|
Chris@0
|
304 if name_or_index.kind_of?(Integer)
|
Chris@0
|
305 @children[name_or_index]
|
Chris@0
|
306 else
|
Chris@0
|
307 @childrenHash[name_or_index]
|
Chris@0
|
308 end
|
Chris@0
|
309 end
|
Chris@0
|
310
|
Chris@0
|
311 # Returns the total number of nodes in this tree, rooted at the receiver
|
Chris@0
|
312 # node.
|
Chris@0
|
313 def size
|
Chris@0
|
314 @children.inject(1) {|sum, node| sum + node.size}
|
Chris@0
|
315 end
|
Chris@0
|
316
|
Chris@0
|
317 # Convenience synonym for Tree#size
|
Chris@0
|
318 def length
|
Chris@0
|
319 size()
|
Chris@0
|
320 end
|
Chris@0
|
321
|
Chris@0
|
322 # Pretty prints the tree starting with the receiver node.
|
Chris@0
|
323 def printTree(level = 0)
|
Chris@0
|
324
|
Chris@0
|
325 if isRoot?
|
Chris@0
|
326 print "*"
|
Chris@0
|
327 else
|
Chris@0
|
328 print "|" unless parent.isLastSibling?
|
Chris@0
|
329 print(' ' * (level - 1) * 4)
|
Chris@0
|
330 print(isLastSibling? ? "+" : "|")
|
Chris@0
|
331 print "---"
|
Chris@0
|
332 print(hasChildren? ? "+" : ">")
|
Chris@0
|
333 end
|
Chris@0
|
334
|
Chris@0
|
335 puts " #{name}"
|
Chris@0
|
336
|
Chris@0
|
337 children { |child| child.printTree(level + 1)}
|
Chris@0
|
338 end
|
Chris@0
|
339
|
Chris@0
|
340 # Returns the root for this tree. Root's root is itself.
|
Chris@0
|
341 def root
|
Chris@0
|
342 root = self
|
Chris@0
|
343 root = root.parent while !root.isRoot?
|
Chris@0
|
344 root
|
Chris@0
|
345 end
|
Chris@0
|
346
|
Chris@0
|
347 # Returns the first sibling for this node. If this is the root node, returns
|
Chris@0
|
348 # itself.
|
Chris@0
|
349 def firstSibling
|
Chris@0
|
350 if isRoot?
|
Chris@0
|
351 self
|
Chris@0
|
352 else
|
Chris@0
|
353 parent.children.first
|
Chris@0
|
354 end
|
Chris@0
|
355 end
|
Chris@0
|
356
|
Chris@0
|
357 # Returns true if this node is the first sibling.
|
Chris@0
|
358 def isFirstSibling?
|
Chris@0
|
359 firstSibling == self
|
Chris@0
|
360 end
|
Chris@0
|
361
|
Chris@0
|
362 # Returns the last sibling for this node. If this node is the root, returns
|
Chris@0
|
363 # itself.
|
Chris@0
|
364 def lastSibling
|
Chris@0
|
365 if isRoot?
|
Chris@0
|
366 self
|
Chris@0
|
367 else
|
Chris@0
|
368 parent.children.last
|
Chris@0
|
369 end
|
Chris@0
|
370 end
|
Chris@0
|
371
|
Chris@0
|
372 # Returns true if his node is the last sibling
|
Chris@0
|
373 def isLastSibling?
|
Chris@0
|
374 lastSibling == self
|
Chris@0
|
375 end
|
Chris@0
|
376
|
Chris@0
|
377 # Returns an array of siblings for this node.
|
Chris@0
|
378 # If a block is provided, yields each of the sibling
|
Chris@0
|
379 # nodes to the block. The root always has nil siblings.
|
Chris@0
|
380 def siblings
|
Chris@0
|
381 return nil if isRoot?
|
Chris@0
|
382 if block_given?
|
Chris@0
|
383 for sibling in parent.children
|
Chris@0
|
384 yield sibling if sibling != self
|
Chris@0
|
385 end
|
Chris@0
|
386 else
|
Chris@0
|
387 siblings = []
|
Chris@0
|
388 parent.children {|sibling| siblings << sibling if sibling != self}
|
Chris@0
|
389 siblings
|
Chris@0
|
390 end
|
Chris@0
|
391 end
|
Chris@0
|
392
|
Chris@0
|
393 # Returns true if this node is the only child of its parent
|
Chris@0
|
394 def isOnlyChild?
|
Chris@0
|
395 parent.children.size == 1
|
Chris@0
|
396 end
|
Chris@0
|
397
|
Chris@0
|
398 # Returns the next sibling for this node. Will return nil if no subsequent
|
Chris@0
|
399 # node is present.
|
Chris@0
|
400 def nextSibling
|
Chris@0
|
401 if myidx = parent.children.index(self)
|
Chris@0
|
402 parent.children.at(myidx + 1)
|
Chris@0
|
403 end
|
Chris@0
|
404 end
|
Chris@0
|
405
|
Chris@0
|
406 # Returns the previous sibling for this node. Will return nil if no
|
Chris@0
|
407 # subsequent node is present.
|
Chris@0
|
408 def previousSibling
|
Chris@0
|
409 if myidx = parent.children.index(self)
|
Chris@0
|
410 parent.children.at(myidx - 1) if myidx > 0
|
Chris@0
|
411 end
|
Chris@0
|
412 end
|
Chris@0
|
413
|
Chris@0
|
414 # Provides a comparision operation for the nodes. Comparision
|
Chris@0
|
415 # is based on the natural character-set ordering for the
|
Chris@0
|
416 # node names.
|
Chris@0
|
417 def <=>(other)
|
Chris@0
|
418 return +1 if other == nil
|
Chris@0
|
419 self.name <=> other.name
|
Chris@0
|
420 end
|
Chris@0
|
421
|
Chris@0
|
422 # Freezes all nodes in the tree
|
Chris@0
|
423 def freezeTree!
|
Chris@0
|
424 each {|node| node.freeze}
|
Chris@0
|
425 end
|
Chris@0
|
426
|
Chris@0
|
427 # Creates the marshal-dump represention of the tree rooted at this node.
|
Chris@0
|
428 def marshal_dump
|
Chris@0
|
429 self.collect { |node| node.createDumpRep }
|
Chris@0
|
430 end
|
Chris@0
|
431
|
Chris@0
|
432 # Creates a dump representation and returns the same as a hash.
|
Chris@0
|
433 def createDumpRep
|
Chris@0
|
434 { :name => @name, :parent => (isRoot? ? nil : @parent.name), :content => Marshal.dump(@content)}
|
Chris@0
|
435 end
|
Chris@0
|
436
|
Chris@0
|
437 # Loads a marshalled dump of the tree and returns the root node of the
|
Chris@0
|
438 # reconstructed tree. See the Marshal class for additional details.
|
Chris@0
|
439 def marshal_load(dumped_tree_array)
|
Chris@0
|
440 nodes = { }
|
Chris@0
|
441 for node_hash in dumped_tree_array do
|
Chris@0
|
442 name = node_hash[:name]
|
Chris@0
|
443 parent_name = node_hash[:parent]
|
Chris@0
|
444 content = Marshal.load(node_hash[:content])
|
Chris@0
|
445
|
Chris@0
|
446 if parent_name then
|
Chris@0
|
447 nodes[name] = current_node = Tree::TreeNode.new(name, content)
|
Chris@0
|
448 nodes[parent_name].add current_node
|
Chris@0
|
449 else
|
Chris@0
|
450 # This is the root node, hence initialize self.
|
Chris@0
|
451 initialize(name, content)
|
Chris@0
|
452
|
Chris@0
|
453 nodes[name] = self # Add self to the list of nodes
|
Chris@0
|
454 end
|
Chris@0
|
455 end
|
Chris@0
|
456 end
|
Chris@0
|
457
|
Chris@0
|
458 # Returns depth of the tree from this node. A single leaf node has a
|
Chris@0
|
459 # depth of 1.
|
Chris@0
|
460 def depth
|
Chris@0
|
461 return 1 if isLeaf?
|
Chris@0
|
462 1 + @children.collect { |child| child.depth }.max
|
Chris@0
|
463 end
|
Chris@0
|
464
|
Chris@0
|
465 # Returns breadth of the tree at this node level. A single node has a
|
Chris@0
|
466 # breadth of 1.
|
Chris@0
|
467 def breadth
|
Chris@0
|
468 return 1 if isRoot?
|
Chris@0
|
469 parent.children.size
|
Chris@0
|
470 end
|
Chris@0
|
471
|
Chris@0
|
472 protected :parent=, :setAsRoot!, :createDumpRep
|
Chris@0
|
473
|
Chris@0
|
474 end
|
Chris@0
|
475 end
|
Chris@0
|
476
|
Chris@0
|
477 # $Log: tree.rb,v $
|
Chris@0
|
478 # Revision 1.29 2007/12/22 00:28:59 anupamsg
|
Chris@0
|
479 # Added more test cases, and enabled ZenTest compatibility.
|
Chris@0
|
480 #
|
Chris@0
|
481 # Revision 1.28 2007/12/20 03:19:33 anupamsg
|
Chris@0
|
482 # * README (Module): Modified the install instructions from source.
|
Chris@0
|
483 # (Module): Updated the minor version number.
|
Chris@0
|
484 #
|
Chris@0
|
485 # Revision 1.27 2007/12/20 03:00:03 anupamsg
|
Chris@0
|
486 # Minor code changes. Removed self_initialize from the protected methods' list.
|
Chris@0
|
487 #
|
Chris@0
|
488 # Revision 1.26 2007/12/20 02:50:04 anupamsg
|
Chris@0
|
489 # (Tree::TreeNode): Removed the spurious self_initialize from the protected list.
|
Chris@0
|
490 #
|
Chris@0
|
491 # Revision 1.25 2007/12/19 20:28:05 anupamsg
|
Chris@0
|
492 # Removed the unnecesary self_initialize method.
|
Chris@0
|
493 #
|
Chris@0
|
494 # Revision 1.24 2007/12/19 06:39:17 anupamsg
|
Chris@0
|
495 # Removed the unnecessary field and record separator constants. Also updated the
|
Chris@0
|
496 # history.txt file.
|
Chris@0
|
497 #
|
Chris@0
|
498 # Revision 1.23 2007/12/19 06:25:00 anupamsg
|
Chris@0
|
499 # (Tree::TreeNode): Minor fix to the comments. Also fixed the private/protected
|
Chris@0
|
500 # scope issue with the createDumpRep method.
|
Chris@0
|
501 #
|
Chris@0
|
502 # Revision 1.22 2007/12/19 06:22:03 anupamsg
|
Chris@0
|
503 # Updated the marshalling logic to correctly handle non-string content. This
|
Chris@0
|
504 # should fix the bug # 15614 ("When dumping with an Object as the content, you get
|
Chris@0
|
505 # a delimiter collision")
|
Chris@0
|
506 #
|
Chris@0
|
507 # Revision 1.21 2007/12/19 02:24:17 anupamsg
|
Chris@0
|
508 # Updated the marshalling logic to handle non-string contents on the nodes.
|
Chris@0
|
509 #
|
Chris@0
|
510 # Revision 1.20 2007/10/10 08:42:57 anupamsg
|
Chris@0
|
511 # Release 0.4.3
|
Chris@0
|
512 #
|
Chris@0
|
513 # Revision 1.19 2007/08/31 01:16:27 anupamsg
|
Chris@0
|
514 # Added breadth and pre-order traversals for the tree. Also added a method
|
Chris@0
|
515 # to return the detached copy of a node from the tree.
|
Chris@0
|
516 #
|
Chris@0
|
517 # Revision 1.18 2007/07/21 05:14:44 anupamsg
|
Chris@0
|
518 # Added a VERSION constant to the Tree module,
|
Chris@0
|
519 # and using the same in the Rakefile.
|
Chris@0
|
520 #
|
Chris@0
|
521 # Revision 1.17 2007/07/21 03:24:25 anupamsg
|
Chris@0
|
522 # Minor edits to parameter names. User visible functionality does not change.
|
Chris@0
|
523 #
|
Chris@0
|
524 # Revision 1.16 2007/07/18 23:38:55 anupamsg
|
Chris@0
|
525 # Minor updates to tree.rb
|
Chris@0
|
526 #
|
Chris@0
|
527 # Revision 1.15 2007/07/18 22:11:50 anupamsg
|
Chris@0
|
528 # Added depth and breadth methods for the TreeNode.
|
Chris@0
|
529 #
|
Chris@0
|
530 # Revision 1.14 2007/07/18 19:33:27 anupamsg
|
Chris@0
|
531 # Added a new binary tree implementation.
|
Chris@0
|
532 #
|
Chris@0
|
533 # Revision 1.13 2007/07/18 07:17:34 anupamsg
|
Chris@0
|
534 # Fixed a issue where TreeNode.ancestors was shadowing Module.ancestors. This method
|
Chris@0
|
535 # has been renamed to TreeNode.parentage.
|
Chris@0
|
536 #
|
Chris@0
|
537 # Revision 1.12 2007/07/17 03:39:28 anupamsg
|
Chris@0
|
538 # Moved the CVS Log keyword to end of the files.
|
Chris@0
|
539 #
|