Tree traversal
You are encouraged to solve this task according to the task description, using any language you may know.
Implement a binary tree where each node carries an integer, and implement preoder, inorder, postorder and level-order traversal. Use those traversals to output the following tree:
1 / \ / \ / \ 2 3 / \ / 4 5 6 / / \ 7 8 9
The correct output should look like this:
preorder: 1 2 4 7 5 3 6 8 9 inorder: 7 4 2 5 1 8 6 9 3 postorder: 7 4 5 2 8 9 6 3 1 level-order: 1 2 3 4 5 6 7 8 9
This article has more information on traversing trees.
Ada
<lang Ada>with Ada.Text_Io; use Ada.Text_Io; with Ada.Unchecked_Deallocation; with Ada.Containers.Doubly_Linked_Lists;
procedure Tree_Traversal is
type Node; type Node_Access is access Node; type Node is record Left : Node_Access := null; Right : Node_Access := null; Data : Integer; end record; procedure Destroy_Tree(N : in out Node_Access) is procedure free is new Ada.Unchecked_Deallocation(Node, Node_Access); begin if N.Left /= null then Destroy_Tree(N.Left); end if; if N.Right /= null then Destroy_Tree(N.Right); end if; Free(N); end Destroy_Tree; function Tree(Value : Integer; Left : Node_Access; Right : Node_Access) return Node_Access is Temp : Node_Access := new Node; begin Temp.Data := Value; Temp.Left := Left; Temp.Right := Right; return Temp; end Tree; procedure Preorder(N : Node_Access) is begin Put(Integer'Image(N.Data)); if N.Left /= null then Preorder(N.Left); end if; if N.Right /= null then Preorder(N.Right); end if; end Preorder; procedure Inorder(N : Node_Access) is begin if N.Left /= null then Inorder(N.Left); end if; Put(Integer'Image(N.Data)); if N.Right /= null then Inorder(N.Right); end if; end Inorder; procedure Postorder(N : Node_Access) is begin if N.Left /= null then Postorder(N.Left); end if; if N.Right /= null then Postorder(N.Right); end if; Put(Integer'Image(N.Data)); end Postorder; procedure Levelorder(N : Node_Access) is package Queues is new Ada.Containers.Doubly_Linked_Lists(Node_Access); use Queues; Node_Queue : List; Next : Node_Access; begin Node_Queue.Append(N); while not Is_Empty(Node_Queue) loop Next := First_Element(Node_Queue); Delete_First(Node_Queue); Put(Integer'Image(Next.Data)); if Next.Left /= null then Node_Queue.Append(Next.Left); end if; if Next.Right /= null then Node_Queue.Append(Next.Right); end if; end loop; end Levelorder; N : Node_Access;
begin
N := Tree(1, Tree(2, Tree(4, Tree(7, null, null), null), Tree(5, null, null)), Tree(3, Tree(6, Tree(8, null, null), Tree(9, null, null)), null)); Put("preorder: "); Preorder(N); New_Line; Put("inorder: "); Inorder(N); New_Line; Put("postorder: "); Postorder(N); New_Line; Put("level order: "); Levelorder(N); New_Line; Destroy_Tree(N);
end Tree_traversal;</lang>
C
<lang c>#include <stdlib.h>
- include <stdio.h>
typedef struct node_s {
int value; struct node_s* left; struct node_s* right;
} *node;
node tree(int v, node l, node r) {
node n = malloc(sizeof(struct node_s)); n->value = v; n->left = l; n->right = r; return n;
}
void destroy_tree(node n) {
if (n->left) destroy_tree(n->left); if (n->right) destroy_tree(n->right); free(n);
}
void preorder(node n, void (*f)(int)) {
f(n->value); if (n->left) preorder(n->left, f); if (n->right) preorder(n->right, f);
}
void inorder(node n, void (*f)(int)) {
if (n->left) inorder(n->left, f); f(n->value); if (n->right) inorder(n->right, f);
}
void postorder(node n, void (*f)(int)) {
if (n->left) postorder(n->left, f); if (n->right) postorder(n->right, f); f(n->value);
}
/* helper queue for levelorder */ typedef struct qnode_s {
struct qnode_s* next; node value;
} *qnode;
typedef struct { qnode begin, end; } queue;
void enqueue(queue* q, node n) {
qnode node = malloc(sizeof(struct qnode_s)); node->value = n; node->next = 0; if (q->end) q->end->next = node; else q->begin = node; q->end = node;
}
node dequeue(queue* q) {
node tmp = q->begin->value; qnode second = q->begin->next; free(q->begin); q->begin = second; if (!q->begin) q->end = 0; return tmp;
}
int queue_empty(queue* q) {
return !q->begin;
}
void levelorder(node n, void(*f)(int)) {
queue nodequeue = {}; enqueue(&nodequeue, n); while (!queue_empty(&nodequeue)) { node next = dequeue(&nodequeue); f(next->value); if (next->left) enqueue(&nodequeue, next->left); if (next->right) enqueue(&nodequeue, next->right); }
}
void print(int n) {
printf("%d ", n);
}
int main() {
node n = tree(1, tree(2, tree(4, tree(7, 0, 0), 0), tree(5, 0, 0)), tree(3, tree(6, tree(8, 0, 0), tree(9, 0, 0)), 0));
printf("preorder: "); preorder(n, print); printf("\n");
printf("inorder: "); inorder(n, print); printf("\n");
printf("postorder: "); postorder(n, print); printf("\n");
printf("level-order: "); levelorder(n, print); printf("\n");
destroy_tree(n);
return 0;
}</lang>
C++
Compiler: g++ (version 4.3.2 20081105 (Red Hat 4.3.2-7))
<lang cpp>#include <boost/scoped_ptr.hpp>
- include <iostream>
- include <queue>
template<typename T> class TreeNode { public:
TreeNode(const T& n, TreeNode* left = NULL, TreeNode* right = NULL) : mValue(n), mLeft(left), mRight(right) {}
T getValue() const { return mValue; }
TreeNode* left() const { return mLeft.get(); }
TreeNode* right() const { return mRight.get(); }
void preorderTraverse() const { std::cout << " " << getValue(); if(mLeft) { mLeft->preorderTraverse(); } if(mRight) { mRight->preorderTraverse(); } }
void inorderTraverse() const { if(mLeft) { mLeft->inorderTraverse(); } std::cout << " " << getValue(); if(mRight) { mRight->inorderTraverse(); } }
void postorderTraverse() const { if(mLeft) { mLeft->postorderTraverse(); } if(mRight) { mRight->postorderTraverse(); } std::cout << " " << getValue(); }
void levelorderTraverse() const { std::queue<const TreeNode*> q; q.push(this);
while(!q.empty()) { const TreeNode* n = q.front(); q.pop(); std::cout << " " << n->getValue();
if(n->left()) { q.push(n->left()); } if(n->right()) { q.push(n->right()); } } }
protected:
T mValue; boost::scoped_ptr<TreeNode> mLeft; boost::scoped_ptr<TreeNode> mRight;
private:
TreeNode();
};
int main() {
TreeNode<int> root(1, new TreeNode<int>(2, new TreeNode<int>(4, new TreeNode<int>(7)), new TreeNode<int>(5)), new TreeNode<int>(3, new TreeNode<int>(6, new TreeNode<int>(8), new TreeNode<int>(9))));
std::cout << "preorder: "; root.preorderTraverse(); std::cout << std::endl;
std::cout << "inorder: "; root.inorderTraverse(); std::cout << std::endl;
std::cout << "postorder: "; root.postorderTraverse(); std::cout << std::endl;
std::cout << "level-order:"; root.levelorderTraverse(); std::cout << std::endl;
return 0;
} </lang>
Common Lisp
<lang lisp>(defun preorder (node f)
(when node (funcall f (first node)) (preorder (second node) f) (preorder (third node) f)))
(defun inorder (node f)
(when node (inorder (second node) f) (funcall f (first node)) (inorder (third node) f)))
(defun postorder (node f)
(when node (postorder (second node) f) (funcall f (first node)) (postorder (third node) f)))
(defun level-order (node f)
(loop with level = (list node) while level do (setf level (loop for node in level when node do (funcall f (first node)) and collect (second node) and collect (third node)))))
(defparameter *tree* '(1 (2 (4 (7))
(5)) (3 (6 (8) (9)))))
(defun show (traversal-function)
(format t "~&~(~A~):~12,0T" traversal-function) (funcall traversal-function *tree* (lambda (value) (format t " ~A" value))))
(map nil #'show '(preorder inorder postorder level-order))</lang>
Output:
preorder: 1 2 4 7 5 3 6 8 9 inorder: 7 4 2 5 1 8 6 9 3 postorder: 7 4 2 5 1 8 6 9 3 level-order: 1 2 3 4 5 6 7 8 9
E
<lang e>def btree := [1, [2, [4, [7, null, null],
null], [5, null, null]], [3, [6, [8, null, null], [9, null, null]], null]]
def backtrackingOrder(node, pre, mid, post) {
switch (node) { match ==null {} match [value, left, right] { pre(value) backtrackingOrder(left, pre, mid, post) mid(value) backtrackingOrder(right, pre, mid, post) post(value) } }
}
def levelOrder(root, func) {
var level := [root].diverge() while (level.size() > 0) { for node in level.removeRun(0) { switch (node) { match ==null {} match [value, left, right] { func(value) level.push(left) level.push(right)
} } } } }
print("preorder: ") backtrackingOrder(btree, fn v { print(" ", v) }, fn _ {}, fn _ {}) println()
print("inorder: ") backtrackingOrder(btree, fn _ {}, fn v { print(" ", v) }, fn _ {}) println()
print("postorder: ") backtrackingOrder(btree, fn _ {}, fn _ {}, fn v { print(" ", v) }) println()
print("level-order:") levelOrder(btree, fn v { print(" ", v) }) println()</lang>
Erlang
<lang erlang> -module(tree_traversal). -export([main/0]). -export([preorder/2, inorder/2, postorder/2, levelorder/2]). -export([tnode/0, tnode/1, tnode/3]).
-define(NEWLINE, io:format("~n")).
tnode() -> {}. tnode(V) -> {node, V, {}, {}}. tnode(V,L,R) -> {node, V, L, R}.
preorder(_,{}) -> ok; preorder(F,{node,V,L,R}) ->
F(V), preorder(F,L), preorder(F,R).
inorder(_,{}) -> ok; inorder(F,{node,V,L,R}) ->
inorder(F,L), F(V), inorder(F,R).
postorder(_,{}) -> ok; postorder(F,{node,V,L,R}) ->
postorder(F,L), postorder(F,R), F(V).
levelorder(_, []) -> []; levelorder(F, [{}|T]) -> levelorder(F, T); levelorder(F, [{node,V,L,R}|T]) ->
F(V), levelorder(F, T++[L,R]);
levelorder(F, X) -> levelorder(F, [X]).
main() ->
Tree = tnode(1, tnode(2, tnode(4, tnode(7), tnode()), tnode(5, tnode(), tnode())), tnode(3, tnode(6, tnode(8), tnode(9)), tnode())), F = fun(X) -> io:format("~p ",[X]) end, preorder(F, Tree), ?NEWLINE, inorder(F, Tree), ?NEWLINE, postorder(F, Tree), ?NEWLINE, levelorder(F, Tree), ?NEWLINE.
</lang>
Output:
1 2 4 7 5 3 6 8 9 7 4 2 5 1 8 6 9 3 7 4 5 2 8 9 6 3 1 1 2 3 4 5 6 7 8 9
Forth
<lang forth> \ binary tree (dictionary)
- node ( l r data -- node ) here >r , , , r> ;
- leaf ( data -- node ) 0 0 rot node ;
- >data ( node -- ) @ ;
- >right ( node -- ) cell+ @ ;
- >left ( node -- ) cell+ cell+ @ ;
- preorder ( xt tree -- )
dup 0= if 2drop exit then 2dup >data swap execute 2dup >left recurse >right recurse ;
- inorder ( xt tree -- )
dup 0= if 2drop exit then 2dup >left recurse 2dup >data swap execute >right recurse ;
- postorder ( xt tree -- )
dup 0= if 2drop exit then 2dup >left recurse 2dup >right recurse >data swap execute ;
- max-depth ( tree -- n )
dup 0= if exit then dup >left recurse swap >right recurse max 1+ ;
defer depthaction
- depthorder ( depth tree -- )
dup 0= if 2drop exit then over 0= if >data depthaction drop else over 1- over >left recurse swap 1- swap >right recurse then ;
- levelorder ( xt tree -- )
swap is depthaction dup max-depth 0 ?do i over depthorder loop drop ;
7 leaf 0 4 node
5 leaf 2 node
8 leaf 9 leaf 6 node
0 3 node 1 node value tree
cr ' . tree preorder \ 1 2 4 7 5 3 6 8 9 cr ' . tree inorder \ 7 4 2 5 1 8 6 9 3 cr ' . tree postorder \ 7 4 5 2 8 9 6 3 1 cr tree max-depth . \ 4 cr ' . tree levelorder \ 1 2 3 4 5 6 7 8 9 </lang>
Haskell
<lang haskell>data Tree a = Empty
| Node { value :: a, left :: Tree a, right :: Tree a }
preorder, inorder, postorder, levelorder :: Tree a -> [a]
preorder Empty = [] preorder (Node v l r) = [v]
++ preorder l ++ preorder r
inorder Empty = [] inorder (Node v l r) = inorder l
++ [v] ++ inorder r
postorder Empty = [] postorder (Node v l r) = postorder l
++ postorder r ++ [v]
levelorder x = loop [x]
where loop [] = [] loop (Empty : xs) = loop xs loop (Node v l r : xs) = v : loop (xs ++ [l,r])
tree :: Tree Int tree = Node 1
(Node 2 (Node 4 (Node 7 Empty Empty) Empty) (Node 5 Empty Empty)) (Node 3 (Node 6 (Node 8 Empty Empty) (Node 9 Empty Empty)) Empty)
main :: IO () main = do print $ preorder tree
print $ inorder tree print $ postorder tree print $ levelorder tree</lang>
Output:
[1,2,4,7,5,3,6,8,9] [7,4,2,5,1,8,6,9,3] [7,4,5,2,8,9,6,3,1] [1,2,3,4,5,6,7,8,9]
J
<lang J>preorder=: ]S:0 postorder=: ([:; postorder&.>@}.) , >@{. levelorder=: ;@({::L:1 _~ [: (/: #@>) <S:1@{::) inorder=: ([:; inorder&.>@("_`(1&{)@.(1<#))) , >@{. , [:; inorder&.>@}.@}.</lang>
Required example:
<lang J>N2=: conjunction def '(<m),(<n),<y' N1=: conjunction def '(<m),<n' L=: adverb def '<m'
N2=: conjunction def '(<m),(<n),<y' N1=: adverb def '(<m),<y' L=: adverb def '<m'
tree=: 1 N2 (2 N2 (4 N1 (7 L)) 5 L) 3 N1 6 N2 (8 L) 9 L</lang>
This tree is organized in a pre-order fashion
preorder tree 1 2 4 7 5 3 6 8 9
post-order is not that much different from pre-order, except that the children must extracted before the parent.
postorder tree 7 4 5 2 9 8 6 3 1
Implementing in-order is more complex because we must sometimes test whether we have any leaves, instead of relying on J's implicit looping over lists
inorder tree 7 4 2 5 1 9 8 6 3
level-order can be accomplished by constructing a map of the locations of the leaves, sorting these map locations by their non-leaf indices and using the result to extract all leaves from the tree. Elements at the same level with the same parent will have the same sort keys and thus be extracted in preorder fashion, which works just fine.
levelorder tree 1 2 3 4 5 6 7 8 9
For J novices, here's the tree instance with a few redundant parenthesis:
tree=: 1 N2 (2 N2 (4 N1 (7 L)) (5 L)) (3 N1 (6 N2 (8 L) (9 L)))
Syntactically, N2 is a binary node expressed as m N2 n y. N1 is a node with a single child, expressed as m N2 y. L is a leaf node, expressed as m L. (And n must be parenthesized if it is not a single word.)
Java
<lang java5>import java.util.Queue; import java.util.LinkedList; public class TreeTraverse {
private static class Node<T>{ public Node<T> left; public Node<T> right; public T data; public Node(T data){ this.data = data; }
public Node<T> getLeft() { return left; }
public void setLeft(Node<T> left) { this.left = left; }
public Node<T> getRight() { return right; }
public void setRight(Node<T> right) { this.right = right; } }
public static void preorder(Node<?> n){ if (n != null) { System.out.print(n.data + " "); preorder(n.getLeft()); preorder(n.getRight()); } } public static void inorder(Node<?> n){ if (n != null) { inorder(n.getLeft()); System.out.print(n.data + " "); inorder(n.getRight()); } } public static void postorder(Node<?> n){ if (n != null){ postorder(n.getLeft()); postorder(n.getRight()); System.out.print(n.data + " "); } } public static void levelorder(Node<?> n) { Queue<Node<?>> nodequeue = new LinkedList<Node<?>>(); if (n != null) nodequeue.add(n); while (!nodequeue.isEmpty()) { Node<?> next = nodequeue.remove(); System.out.print(next.data + " "); if (next.getLeft() != null) { nodequeue.add(next.getLeft()); } if (next.getRight() != null) { nodequeue.add(next.getRight()); } } } public static void main(String[] args){ Node<Integer> one = new Node<Integer>(1); Node<Integer> two = new Node<Integer>(2); Node<Integer> three = new Node<Integer>(3); Node<Integer> four = new Node<Integer>(4); Node<Integer> five = new Node<Integer>(5); Node<Integer> six = new Node<Integer>(6); Node<Integer> seven = new Node<Integer>(7); Node<Integer> eight = new Node<Integer>(8); Node<Integer> nine = new Node<Integer>(9); one.setLeft(two); one.setRight(three); two.setLeft(four); two.setRight(five); three.setLeft(six); four.setLeft(seven); six.setLeft(eight); six.setRight(nine); preorder(one); System.out.println(); inorder(one); System.out.println(); postorder(one); System.out.println(); levelorder(one); System.out.println(); }
}</lang> Output:
1 2 4 7 5 3 6 8 9 7 4 2 5 1 8 6 9 3 7 4 5 2 8 9 6 3 1 1 2 3 4 5 6 7 8 9
Logo
<lang logo>
- nodes are [data left right], use "first" to get data
to node.left :node
if empty? butfirst :node [output []] output first butfirst :node
end to node.right :node
if empty? butfirst :node [output []] if empty? butfirst butfirst :node [output []] output first butfirst butfirst :node
end to max :a :b
output ifelse :a > :b [:a] [:b]
end to tree.depth :tree
if empty? :tree [output 0] output 1 + max tree.depth node.left :tree tree.depth node.right :tree
end
to pre.order :tree :action
if empty? :tree [stop] invoke :action first :tree pre.order node.left :tree :action pre.order node.right :tree :action
end to in.order :tree :action
if empty? :tree [stop] pre.order node.left :tree :action invoke :action first :tree pre.order node.right :tree :action
end to post.order :tree :action
if empty? :tree [stop] pre.order node.left :tree :action pre.order node.right :tree :action invoke :action first :tree
end to at.depth :n :tree :action
if empty? :tree [stop] ifelse :n = 1 [invoke :action first :tree] [ at.depth :n-1 node.left :tree :action at.depth :n-1 node.right :tree :action ]
end to level.order :tree :action
for [i 1 [tree.depth :tree]] [at.depth :i :tree :action]
end
make "tree [1 [2 [4 [7]]
[5]] [3 [6 [8] [9]]]]
pre.order :tree [(type ? "| |)] (print) in.order :tree [(type ? "| |)] (print) post.order :tree [(type ? "| |)] (print)
level.order :tree [(type ? "| |)] (print) </lang>
OCaml
<lang ocaml>type 'a tree = Empty
| Node of 'a * 'a tree * 'a tree
let rec preorder f = function
Empty -> () | Node (v,l,r) -> f v; preorder f l; preorder f r
let rec inorder f = function
Empty -> () | Node (v,l,r) -> inorder f l; f v; inorder f r
let rec postorder f = function
Empty -> () | Node (v,l,r) -> preorder f l; preorder f r; f v
let levelorder f x =
let queue = Queue.create () in Queue.add x queue; while not (Queue.is_empty queue) do match Queue.take queue with Empty -> () | Node (v,l,r) -> f v; Queue.add l queue; Queue.add r queue done
let tree =
Node (1, Node (2, Node (4, Node (7, Empty, Empty), Empty), Node (5, Empty, Empty)), Node (3, Node (6, Node (8, Empty, Empty), Node (9, Empty, Empty)), Empty))
let () =
preorder (Printf.printf "%d ") tree; print_newline (); inorder (Printf.printf "%d ") tree; print_newline (); postorder (Printf.printf "%d ") tree; print_newline (); levelorder (Printf.printf "%d ") tree; print_newline ()</lang>
Output:
1 2 4 7 5 3 6 8 9 7 4 2 5 1 8 6 9 3 2 4 7 5 3 6 8 9 1 1 2 3 4 5 6 7 8 9
Python
<lang python> from collections import namedtuple from sys import stdout
Node = namedtuple('Node', 'data, left, right') tree = Node(1,
Node(2, Node(4, Node(7, None, None), None), Node(5, None, None)), Node(3, Node(6, Node(8, None, None), Node(9, None, None)), None))
def printwithspace(i):
stdout.write("%i " % i)
def preorder(node, visitor = printwithspace):
if node is not None: visitor(node.data) preorder(node.left, visitor) preorder(node.right, visitor)
def inorder(node, visitor = printwithspace):
if node is not None: inorder(node.left, visitor) visitor(node.data) inorder(node.right, visitor)
def postorder(node, visitor = printwithspace):
if node is not None: postorder(node.left, visitor) postorder(node.right, visitor) visitor(node.data)
def levelorder(node, more=None, visitor = printwithspace):
if node is not None: if more is None: more = [] more += [node.left, node.right] visitor(node.data) if more: levelorder(more[0], more[1:], visitor)
stdout.write(' preorder: ') preorder(tree) stdout.write('\n inorder: ') inorder(tree) stdout.write('\n postorder: ') postorder(tree) stdout.write('\nlevelorder: ') levelorder(tree) stdout.write('\n') </lang>
Sample output:
preorder: 1 2 4 7 5 3 6 8 9 inorder: 7 4 2 5 1 8 6 9 3 postorder: 7 4 5 2 8 9 6 3 1 levelorder: 1 2 3 4 5 6 7 8 9
Ruby
<lang ruby>class BinaryTreeNode
def initialize(value, left=nil, right=nil) @value, @left, @right = value, left, right end attr_reader :value, :left, :right
def self.from_array(nested_list) value, left, right = nested_list if value self.new(value, self.from_array(left), self.from_array(right)) end end def walk_nodes(order, &block) order.each do |node| case node when :left then left && left.walk_nodes(order, &block) when :self then yield self when :right then right && right.walk_nodes(order, &block) end end end def each_preorder(&b) ; walk_nodes([:self, :left, :right], &b) ; end def each_inorder(&b) ; walk_nodes([:left, :self, :right], &b) ; end def each_postorder(&b) ; walk_nodes([:left, :right, :self], &b) ; end def each_levelorder queue = [self] until queue.empty? node = queue.shift yield node queue << node.left if node.left queue << node.right if node.right end end
end
root = BinaryTreeNode.from_array [1, [2, [4, 7], [5]], [3, [6, [8], [9]]]]
%w{each_preorder each_inorder each_postorder each_levelorder}.each {|mthd|
printf "%-11s ", mthd[5..-1] + ':' root.send(mthd) {|node| print "#{node.value} "} puts
}</lang>
Output:
preorder: 1 2 4 7 5 3 6 8 9 inorder: 7 4 2 5 1 8 6 9 3 postorder: 7 4 5 2 8 9 6 3 1 levelorder: 1 2 3 4 5 6 7 8 9
Tcl
<lang tcl>oo::class create tree {
# Basic tree data structure stuff... variable val l r constructor {value {left {}} {right {}}} {
set val $value set l $left set r $right
} method value {} {return $val} method left {} {return $l} method right {} {return $r} destructor {
if {$l ne ""} {$l destroy} if {$r ne ""} {$r destroy}
}
# Traversal methods method preorder {varName script {level 0}} {
upvar [incr level] $varName var set var $val uplevel $level $script if {$l ne ""} {$l preorder $varName $script $level} if {$r ne ""} {$r preorder $varName $script $level}
} method inorder {varName script {level 0}} {
upvar [incr level] $varName var if {$l ne ""} {$l inorder $varName $script $level} set var $val uplevel $level $script if {$r ne ""} {$r inorder $varName $script $level}
} method postorder {varName script {level 0}} {
upvar [incr level] $varName var if {$l ne ""} {$l postorder $varName $script $level} if {$r ne ""} {$r postorder $varName $script $level} set var $val uplevel $level $script
} method levelorder {varName script} {
upvar 1 $varName var set nodes [list [self]]; # A queue of nodes to process while {[llength $nodes] > 0} { set nodes [lassign $nodes n] set var [$n value] uplevel 1 $script if {[$n left] ne ""} {lappend nodes [$n left]} if {[$n right] ne ""} {lappend nodes [$n right]} }
}
}</lang>
Note that in Tcl it is conventional to handle performing something “for each element” by evaluating a script in the caller's scope for each node after setting a caller-nominated variable to the value for that iteration. Doing this transparently while recursing requires the use of a varying ‘level’ parameter to upvar
and uplevel
, but makes for compact and clear code.
Demo code to satisfy the official challenge instance: <lang tcl># Helpers to make construction and listing of a whole tree simpler proc Tree nested {
lassign $nested v l r if {$l ne ""} {set l [Tree $l]} if {$r ne ""} {set r [Tree $r]} tree new $v $l $r
} proc Listify {tree order} {
set list {} $tree $order v {
lappend list $v
} return $list
}
- Make a tree, print it a few ways, and destroy the tree
set t [Tree {1 {2 {4 7} 5} {3 {6 8 9}}}] puts "preorder: [Listify $t preorder]" puts "inorder: [Listify $t inorder]" puts "postorder: [Listify $t postorder]" puts "level-order: [Listify $t levelorder]" $t destroy</lang> Output:
preorder: 1 2 4 7 5 3 6 8 9 inorder: 7 4 2 5 1 8 6 9 3 postorder: 7 4 5 2 8 9 6 3 1 level-order: 1 2 3 4 5 6 7 8 9
Unix Shell
Bash (also "sh" on most Unix systems) has arrays. We implement a node as an association between three arrays: left, right, and value. <lang bash>left=() right=() value=()
- node node#, left#, right#, value
- if value is empty, use node#
node() {
nx=${1:-'Missing node index'} leftx=${2} rightx=${3} val=${4:-$1} value[$nx]="$val" left[$nx]="$leftx" right[$nx]="$rightx"
}
- define the tree
node 1 2 3 node 2 4 5 node 3 6 node 4 7 node 5 node 6 8 9 node 7 node 8 node 9
- walk NODE# ORDER
walk() {
local nx=${1-"Missing index"} shift for branch in "$@" ; do case "$branch" in left) if [[ "${left[$nx]}" ]]; then walk ${left[$nx]} $@ ; fi ;; right) if [[ "${right[$nx]}" ]]; then walk ${right[$nx]} $@ ; fi ;; self) printf "%d " "${value[$nx]}" ;; esac done
}
apush() {
local var="$1" eval "$var=( \"\${$var[@]}\" \"$2\" )"
}
showname() {
printf "%-12s " "$1:"
}
showdata() {
showname "$1" shift walk "$@" echo
}
preorder() { showdata $FUNCNAME $1 self left right ; } inorder() { showdata $FUNCNAME $1 left self right ; } postorder() { showdata $FUNCNAME $1 left right self ; } levelorder() {
showname 'level-order' queue=( $1 ) x=0 while [[ $x < ${#queue[*]} ]]; do value="${queue[$x]}" printf "%d " "$value" for more in "${left[$value]}" "${right[$value]}" ; do if -n "$more" ; then
apush queue "$more"
fi done : $((x++)) done echo
}
preorder 1 inorder 1 postorder 1 levelorder 1</lang> The output: <lang "bash">preorder: 1 2 4 7 5 3 6 8 9 inorder: 7 4 2 5 1 8 6 9 3 postorder: 7 4 5 2 8 9 6 3 1 level-order: 1 2 3 4 5 6 7 8 9 </lang>
Ursala
Ursala has built-in notation for trees and is perfect for whipping up little tree walking functions. <lang Ursala> tree =
1^:<
2^: <4^: <7^: <>, 0>, 5^: <>>, 3^: <6^: <8^: <>, 9^: <>>, 0>>
pre = ~&dvLPCo post = ~&vLPdNCTo in = ~&vvhPdvtL2CTiQo lev = ~&iNCaadSPfavSLiF3RTaq
- cast %nLL
main = <.pre,in,post,lev> tree </lang> output:
< <1,2,4,7,5,3,6,8,9>, <7,4,2,5,1,8,6,9,3>, <7,4,5,2,8,9,6,3,1>, <1,2,3,4,5,6,7,8,9>>