Current Version 2.12
zip
tar gzip
Author: Evan Rempel erempel@UVic.CA
This package is intended to be a building block for any and all hierachical structures. It has a slightly different interface than most programmers are used to, but I believe it to be functionally complete.
By definition, a tree is a single element, with zero or more trees as children. Using this definition, there is no NULL tree.
As examples I will produe an XML parser that will produce trees, and a binary search tree package.
For those that are working on large trees, I have included a BigO classification for each of the routines. I was recently bitten by a O(n2) tree operation in a perl library :-( and wanted to save others of this problem.
::Tree::isTree treeToken
O(1)
::Tree::isRoot treeToken
O(1)
::Tree::isLeaf treeToken
O(1)
::Tree::create name ?value?
O(1)
::Tree::destroy treeToken
O(n)
::Tree::root treeToken
O(log n) for balanced trees. The degenerative case is O(n).
::Tree::prune treeToken
O(n) where n is the number of siblings.
::Tree::graft parentToken childToken
O(log n) for balanced trees. The degenerative case is O(n).
::Tree::parent treeToken
O(1)
::Tree::child treeToken name
O(1)
::Tree::children treeToken ?options?
::Tree::children treeToken ?-pattern? pattern ?options?
O(1) unless -order or -sort are used, then O(n) plus the O(sort/order) where n is the number of children.
-pattern pattern
-order names
There is no order defined for children that have the same names.
The -order and -sort options may not both be specified.
-sort "command options"
command options nameListThe sort command specified may return names that were not present in the nameList. This will cause null children to be returned in the place of the non-existant names.
There is no order defined for children that have the same names.
The -order and -sort options may not both be specified.
::Tree::exist treeToken name ?childVar?
O(1)
The followig two segments of code are equivilent;
if {[::Tree::exist $myTree childName]} then { set childList [::Tree::children $myTree childName] ... some code ... }and
if {[::Tree::exist $myTree childName childList]} then { ... some code ... }
::Tree::name treeToken
::Tree::name treeToken ?name?
In the first form, return the name of the tree represented by treeToken.
In the second form, set the name of the treeToken to name. Return the name of the tree prior to the change.
O(1)
::Tree::attribute tree
::Tree::attribute tree ?attribute?
::Tree::attribute tree attribute ?value?
array set MyArray [::Tree::attribute $someTree]
In the second form, return the value of the user attribute specified. The attribute named value is the default attribute used in the ::Tree::create routine and the walk routine.
In the third form, set the value of the of the tree attribute to be value. Return the value of the tree attribute prior to the change.
O(1)
::Tree::attributeExist tree attribute
O(1)
::Tree::attributeUnset tree attribute
O(1)
::Tree::list tree pattern
::Tree::list tree pattern ?attribute?
O(n) where n is the number of children.
This is equivilent to the following code segment;
proc ::Tree::list {tree childName attribute} {
set myList {}
foreach child [::Tree::children $myTree $childName] {
lappend myList [::Tree::attribute $child $attribute]
}
return $myList
}
::Tree::appendAttribute tree attribute value
O(1)
::Tree::height tree
O(n)
O(log n) for balanced trees. The degenerative case is O(n).
::Tree::format treeToken
O(n)
The following code will produce the output below.
set myTree [::Tree::create employee]
set birthday [::Tree::graft $myTree [::Tree::create birthday happy]]
::Tree::attribute $birthday type julian
::Tree::graft $birthday [::Tree::create year 1971]
::Tree::graft $birthday [::Tree::create month March]
::Tree::graft $birthday [::Tree::create day 17]
::Tree::graft $myTree [::Tree::create name "Sam Smith"]
::Tree::graft $myTree [::Tree::create empNumber "12345"]
puts [::Tree::format $myTree]
Would produce the output;
<employee>
<birthday type="julian">happy
<year>1971</year>
<month>March</month>
<day>17</day>
</birthday>
<name>Sam Smith</name>
<empNumber>12345</empNumber>
</employee>
::Tree::walk tree depth options
::Tree::walk tree level options
This routine will walk through the tree, following a depth order,
or a level order traversal, calling the specified commands for
each tree that is visited.
If any of the -preCall, -inCall or -postCall commands returns a non-zero, the traverse is canceled and the tree that the non-zero return was performed on is returned.
O(n) * ( O(preCall/inCall/postCall) + O(sort/order/arrange) )
-preCall "command args"
command args tree depth
-inCall "command args"
command args tree depth inCallIndex
Note: If the -order option is specified, the command is called once between each of the children in the -order list, regardless of whether or not the child actually exists. This could result in multiple back to back calls to command.
command args tree depth
-postCall "command args"
command args tree depth
-singleInCall boolean
-order names
Generally, the -order option is only useful if the names of the immediate children are unique within the immediate tree, but common to all trees and sub-trees. Also see the -InCall option. A common usage for this option is to binary trees to ensure that an in-order traversal visits the parent of a right node first, even if the left node is not present.
There is no order defined for children that have the same names.
The -order and -sort options may not both be specified.
-sort "command options"
command options nameListThe sort command specified may return names that were not present in the nameList. This will affect the traversal the same way that non-existant names in the -order option do. Any children that are not returned by this routine are appended to the list that the sort command returns.
-arrange "command options"
command options treeThe arrange command specified may return names that were not present in the nameList. This will affect the traversal the same way that non-existant names in the -order option do. Any children that are not returned by this routine are appended to the list that the arrange command returns.
There is no order defined for children that have the same names.
Only one of the -order, -sort or -arrange options may be specified.
The ::Tree::format routine could be written as the following, however, using ::Tree::format is an order of magnitude faster;
proc MyFormat { tree } {
proc InOrder { collect tree depth count} {
upvar $collect output
if {[::Tree::isLeaf $tree]} then {
set offsetString "[string repeat " " $depth][string repeat " " $depth]"
array set attributes [::Tree::attribute $tree]
set attribString ""
foreach attributeName [array names attributes] {
if {$attributeName != "value"} then {
append attribString " $attributeName=\"$attributes($attributeName)\""
}
}
append output "${offsetString}<[::Tree::name $tree]$attribString>[::Tree::attribute $tree value]</[::Tree::name $tree]>\n"
}
return 0
}
proc PostOrder { collect tree depth } {
upvar $collect output
if {![::Tree::isLeaf $tree]} then {
set offsetString "[string repeat " " $depth][string repeat " " $depth]"
append output "${offsetString}</[::Tree::name $tree]>\n"
}
return 0
}
proc PreOrder { collect tree depth } {
upvar $collect output
if {![::Tree::isLeaf $tree]} then {
set offsetString "[string repeat " " $depth][string repeat " " $depth]"
array set attributes [::Tree::attribute $tree]
set attribString ""
foreach attributeName [array names attributes] {
if {$attributeName != "value"} then {
append attribString " $attributeName=\"$attributes($attributeName)\""
}
}
append output "${offsetString}<[::Tree::name $tree]$attribString>[::Tree::attribute $tree value]\n"
}
return 0
}
set answer ""
::Tree::walk $tree depth -inCall "InOrder answer" -preCall "PreOrder answer" -postCall "PostOrder answer" -singleInCall 0
return $answer
}
Version 2.12 - Apr 10, 2003
Version 2.11 - Feb 13, 2003
Version 2.10 - Oct 29, 2002
Version 2.9.1 - July 27, 2002
Version 2.9 - June 9, 2002
Version 2.8 - Mar 12, 2002
Version 2.7 - Feb 9, 2002
Version 2.6 - Jan 30, 2002
Version 2.5 - Jan 22, 2002
Version 2.4 - October 21, 2001
Version 2.3.1 - Aug 24, 2001
Version 2.3 - July 3, 2001
Version 2.2 - June 18, 2001
Tested with TCL 8.4.1 Tree 2.12 - same as 2.11 Tree 2.11 Create: 42 microseconds per iteration Destroy: 39 microseconds per iteration Destroy with children: 140 microseconds per iteration isTree: 6 microseconds per iteration isRoot: 10 microseconds per iteration isLeaf: 11 microseconds per iteration root: 29 microseconds per iteration Graft (keeping): 86 microseconds Pruning 10000 trees Prune: 1265 microseconds Destroy: 36 microseconds parent: 10 microseconds per iteration child: 14 microseconds per iteration children all: 23 microseconds per iteration children static: 45 microseconds per iteration children wild card: 29 microseconds per iteration children all with sort: 116 microseconds per iteration children all with order: 118 microseconds per iteration exist: 36 microseconds per iteration exist return: 60 microseconds per iteration name: 17 microseconds per iteration Attribute set: 26 microseconds per iteration All attributes: 66 microseconds per iteration Single attribute: 23 microseconds per iteration Unset attribute: 16 microseconds per iteration list static: 44 microseconds per iteration list wild card: 71 microseconds per iteration list unknown value: 71 microseconds per iteration appendAttribute: 13 microseconds per iteration height: 179 microseconds per iteration depth: 55 microseconds per iteration format: 1236 microseconds per iteration walk - none: 711 microseconds per iteration walk - pre: 1358 microseconds per iteration walk - in: 1384 microseconds per iteration walk - post: 1364 microseconds per iteration walk - pre, in, post: 2534 microseconds per iteration walk - pre, in, post with sort: 2942 microseconds per iteration walk level: 1431 microseconds per iteration walk level - sort: 1616 microseconds per iteration Tree: 2.10 Create: 42 microseconds per iteration Destroy: 50 microseconds per iteration Destroy with children: 146 microseconds per iteration isTree: 6 microseconds per iteration isRoot: 11 microseconds per iteration isLeaf: 11 microseconds per iteration root: 29 microseconds per iteration Graft (keeping): 84 microseconds per iteration Pruning 10000 trees Prune (list): 1351 microseconds per iteration Destroy: 45 microseconds per iteration parent: 10 microseconds per iteration child: 14 microseconds per iteration children all: 23 microseconds per iteration children static: 47 microseconds per iteration children wild card: 30 microseconds per iteration children all with sort: 117 microseconds per iteration children all with order: 118 microseconds per iteration exist: 37 microseconds per iteration exist return: 61 microseconds per iteration name: 17 microseconds per iteration Attribute set: 26 microseconds per iteration All attributes: 67 microseconds per iteration Single attribute: 23 microseconds per iteration Unset attribute: 17 microseconds per iteration list static: 44 microseconds per iteration list wild card: 72 microseconds per iteration list unknown value: 72 microseconds per iteration appendAttribute: 13 microseconds per iteration height: 180 microseconds per iteration depth: 55 microseconds per iteration format: 1317 microseconds per iteration walk - none: 703 microseconds per iteration walk - pre: 1334 microseconds per iteration walk - in: 1347 microseconds per iteration walk - post: 1328 microseconds per iteration walk - pre, in, post: 2527 microseconds per iteration walk - pre, in, post with sort: 2830 microseconds per iteration walk level: 1377 microseconds per iteration walk level - sort: 1556 microseconds per iteration Tree: 2.9 Create: 59 microseconds per iteration Destroy: 57 microseconds per iteration Destroy with children: 173 microseconds per iteration isTree: 6 microseconds per iteration isRoot: 18 microseconds per iteration isLeaf: 17 microseconds per iteration root: 29 microseconds per iteration Prune-graft individual: 145 microseconds per iteration Graft (keeping): 150 microseconds per iteration Pruning 10000 trees Prune (list): 1284 microseconds per iteration Destroy: 59 microseconds per iteration parent: 10 microseconds per iteration child: 14 microseconds per iteration children all: 22 microseconds per iteration children static: 58 microseconds per iteration children wild card: 37 microseconds per iteration children all with sort: 130 microseconds per iteration children all with order: 122 microseconds per iteration exist: 37 microseconds per iteration exist return: 61 microseconds per iteration name: 20 microseconds per iteration Attribute set: 28 microseconds per iteration All attributes: 78 microseconds per iteration Single attribute: 26 microseconds per iteration Unset attribute: 19 microseconds per iteration list static: 47 microseconds per iteration list wild card: 75 microseconds per iteration list unknown value: 77 microseconds per iteration appendAttribute: 16 microseconds per iteration height: 186 microseconds per iteration depth: 55 microseconds per iteration format: 1344 microseconds per iteration walk - none: 812 microseconds per iteration walk - pre: 1438 microseconds per iteration walk - in: 1453 microseconds per iteration walk - post: 1438 microseconds per iteration walk - pre, in, post: 2593 microseconds per iteration walk - pre, in, post with sort: 2907 microseconds per iteration walk level: 1343 microseconds per iteration walk level - sort: 1594 microseconds per iteration Tested with TCL 8.3.4 Tree: 2.9 Create: 68 microseconds per iteration Destroy: 63 microseconds per iteration Destroy with children: 189 microseconds per iteration isTree: 7 microseconds per iteration isRoot: 21 microseconds per iteration isLeaf: 24 microseconds per iteration root: 41 microseconds per iteration prune-graft: 54 microseconds per iteration parent: 18 microseconds per iteration child: 23 microseconds per iteration children all: 33 microseconds per iteration children static: 63 microseconds per iteration children wild card: 50 microseconds per iteration children all with sort: 143 microseconds per iteration children all with order: 139 microseconds per iteration exist: 37 microseconds per iteration exist return: 60 microseconds per iteration name: 22 microseconds per iteration Attribute set: 33 microseconds per iteration All attributes: 74 microseconds per iteration Single attribute: 29 microseconds per iteration list static: 49 microseconds per iteration list wild card: 85 microseconds per iteration list unknown value: 86 microseconds per iteration appendAttribute: 23 microseconds per iteration height: 255 microseconds per iteration depth: 76 microseconds per iteration format: 1704 microseconds per iteration walk - none: 1250 microseconds per iteration walk - pre: 2046 microseconds per iteration walk - in: 2094 microseconds per iteration walk - post: 2031 microseconds per iteration walk - pre, in, post: 3500 microseconds per iteration walk - pre, in, post with sort: 3782 microseconds per iteration walk level: 1750 microseconds per iteration walk level - sort: 2093 microseconds per iteration Tree: 2.8 Create-destroy: 110 microseconds per iteration Create: 103 microseconds per iteration Destroy: 69 microseconds per iteration Destroy with children: 192 microseconds per iteration isTree: 8 microseconds per iteration isRoot: 21 microseconds per iteration isLeaf: 24 microseconds per iteration root: 41 microseconds per iteration prune-graft: 55 microseconds per iteration parent: 18 microseconds per iteration child: 22 microseconds per iteration children all: 40 microseconds per iteration children static: 60 microseconds per iteration children wild card: 47 microseconds per iteration exist: 37 microseconds per iteration exist return: 60 microseconds per iteration name: 22 microseconds per iteration Attribute set: 33 microseconds per iteration All attributes: 111 microseconds per iteration Single attribute: 29 microseconds per iteration list static: 53 microseconds per iteration list wild card: 86 microseconds per iteration list unknown value: 88 microseconds per iteration appendAttribute: 23 microseconds per iteration height: 289 microseconds per iteration depth: 75 microseconds per iteration format: 1906 microseconds per iteration walk - none: 1407 microseconds per iteration walk - pre: 2437 microseconds per iteration walk - in: 2485 microseconds per iteration walk - post: 2469 microseconds per iteration walk - pre, in, post: 4281 microseconds per iteration walk - pre, in, post with sort: 4719 microseconds per iteration walk level: 1828 microseconds per iteration walk level - sort: 2266 microseconds per iteration Tree: 2.7 Create-destroy: 122 microseconds per iteration isTree: 8 microseconds per iteration isRoot: 21 microseconds per iteration isLeaf: 19 microseconds per iteration root: 38 microseconds per iteration prune-graft: 44 microseconds per iteration parent: 18 microseconds per iteration child: 22 microseconds per iteration children all: 21 microseconds per iteration children static: 37 microseconds per iteration children wild card: 48 microseconds per iteration exist: 40 microseconds per iteration exist return: 65 microseconds per iteration name: 26 microseconds per iteration Attribute set: 37 microseconds per iteration All attributes: 114 microseconds per iteration Single attribute: 34 microseconds per iteration list static: 58 microseconds per iteration list wild card: 102 microseconds per iteration list unknown value: 89 microseconds per iteration appendAttribute: 27 microseconds per iteration height: 219 microseconds per iteration depth: 79 microseconds per iteration Tree: 2.6 Create-destroy: 129 microseconds per iteration isTree: 11 microseconds per iteration isRoot: 18 microseconds per iteration isLeaf: 20 microseconds per iteration root: 60 microseconds per iteration prune-graft: 48 microseconds per iteration parent: 18 microseconds per iteration child: 22 microseconds per iteration children all: 50 microseconds per iteration children static: 38 microseconds per iteration children wild card: 49 microseconds per iteration exist: 37 microseconds per iteration exist return: 43 microseconds per iteration name: 30 microseconds per iteration Attribute set: 41 microseconds per iteration All attributes: 118 microseconds per iteration Single attribute: 38 microseconds per iteration list static: 54 microseconds per iteration list wild card: 87 microseconds per iteration appendAttribute: 31 microseconds per iteration height: 325 microseconds per iteration depth: 86 microseconds per iteration Tree: 2.5 Create-destroy: 119 microseconds per iteration isTree: 11 microseconds per iteration isRoot: 17 microseconds per iteration isLeaf: 20 microseconds per iteration root: 59 microseconds per iteration prune-graft: 47 microseconds per iteration parent: 17 microseconds per iteration child: 22 microseconds per iteration children all: 18 microseconds per iteration exist: 36 microseconds per iteration exist return: 41 microseconds per iteration name: 30 microseconds per iteration Attribute set: 41 microseconds per iteration All attributes: 119 microseconds per iteration Single attribute: 37 microseconds per iteration list static: 40 microseconds per iteration appendAttribute: 31 microseconds per iteration height: 253 microseconds per iteration depth: 85 microseconds per iteration Tree: 2.4 Create-destroy: 119 microseconds per iteration isTree: 11 microseconds per iteration isRoot: 17 microseconds per iteration isLeaf: 21 microseconds per iteration root: 60 microseconds per iteration prune-graft: 47 microseconds per iteration parent: 18 microseconds per iteration child: 21 microseconds per iteration children all: 18 microseconds per iteration exist: 37 microseconds per iteration exist return: 41 microseconds per iteration name: 30 microseconds per iteration Attribute set: 41 microseconds per iteration All attributes: 119 microseconds per iteration Single attribute: 37 microseconds per iteration list static: 40 microseconds per iteration appendAttribute: 30 microseconds per iteration height: 254 microseconds per iteration depth: 85 microseconds per iteration