# In this example, we don't encapsulate binary trees as objects; instead, we have a# convention on how to store them as arrays, and we namespace the functions that# operate on those data structures.binary_tree = preorder:(tree, visit)->returnunless tree?[node, left, right] = tree visit node binary_tree.preorder left, visit binary_tree.preorder right, visit

// 'visitor' can be any kind of callable or it uses a default visitor.// TNode can be any kind of Node, with data, left and right fields,// so this is more generic than a member function of Node.void backtrackingOrder(Visit v, TNode, TyF=void*)(in TNode node, TyF visitor=null){alias trueVisitor = Select!(is(TyF ==void*), show, visitor);if(node !isnull){staticif(v == Visit.pre) trueVisitor(node.data); backtrackingOrder!v(node.left, visitor);staticif(v == Visit.inv) trueVisitor(node.data); backtrackingOrder!v(node.right, visitor);staticif(v == Visit.post) trueVisitor(node.data);}}

print_preorder-- Recursively prints the value of the node and all its children in preorderdo Io.put_string(" "+ value.out)if has_left_child then left_child.print_preorderendif has_right_child then right_child.print_preorderendend

print_inorder-- Recursively prints the value of the node and all its children in inorderdoif has_left_child then left_child.print_inorderend Io.put_string(" "+ value.out)if has_right_child then right_child.print_inorderendend

print_postorder-- Recursively prints the value of the node and all its children in postorderdoif has_left_child then left_child.print_postorderendif has_right_child then right_child.print_postorderend Io.put_string(" "+ value.out)end

For many years it has been routine to hear murmured exchanges that "Fortran is not a recursive language", which is rather odd because any computer language that allows arithmetic expressions in the usual infix notation as learnt at primary school is fundamentally recursive. Moreover, nothing in Fortran's syntax prevents recursion: routines can invoke each other or themselves without difficulty. It is the implementation that is at fault. Typically, a Fortran compiler produces code for a computer lacking an in-built stack mechanism and this became a habit. For instance, on the IBM1130, entry to a routine was via a BSI instruction, "Branch and Save IAR", which placed the return address (the value of the Instruction Address Register, IAR) at the routine's entry point and commenced execution at the following address. For the IBM360 et al, the instruction was BALR, "Branch and Load Register" (I always edited listings to read BALROG, ahem) whereby the return address was loaded into a specified register. Should such a routine then invoke itself in the same manner, then the first return address will be overwritten by the new address. Only if the routine included special code to save multiple return addresses could such recursion work.

In other words, there has never been any problem with recursive invocations in Fortran, merely in organising the correct return from them. Unless you used the Burroughs Fortran compiler, which being for a computer whose hardware employed a stack mechanism, meant that it all just worked and there was no reason to prevent recursion from working. Except for a large system for the formal manipulation of mathematical expressions, whose major components repeatedly invoked each other without ever bothering to return: large jobs failed via stack overflow!

Otherwise, one can always write detailed code that gives effect to recursive usage, typically involving a variable called SP and an array called STACK. Oddly, such proceedings for the QuickSort algorithm are often declared to be "iterative", presumably because the absence of formally-declared recursive phrases blocks recognition of recursive action.

In the example source, the mainline, GORILLA, does its recursion via array twiddling and in that spirit, uses multiple lists for the "level" style traversal so that one tree clamber only need be made, whereas the recursive equivalent cheats by commanding one clamber for each level. The recursive routines store their state in part via the position within their code - that is, before, between, or after the recursive invocations, and are much easier to compare. Rather than litter the source with separate routines and their declarations for each of the four styles required, routine TARZAN has the four versions together for easy comparison, distinguished by a CASE statement. Actually, the code could be even more compact as in

But that would cloud the simplicity of each separate version, and would be extra messy with the fourth option included. On the other hand, the requirements for formal recursion carry the cost of the entry/exit protocol and moreover must do so for every invocation (though there is sometimes opportunity for end-recursion to be converted into a secret "go to") - avoiding this is why every invocation of TARZAN first checks that it has a live link, rather than coding this once only within TARZAN to return immediately when invoked with a dead link - whereas the array twiddling via SP deals only with what is required and notably, avoids raising the stack if it can. Further, the GORILLA version can if necessary maintain additional information, as is needed for the postorder traversal where, not having state information stored via position in the code (as with the recursive version) it needs to know whether it is returning to a node from which it departed via the rightwards link and so is in the post-traversal state and thus due a postorder action. This could involve an auxiliary array, but here is handled by taking advantage of the sign of the STACK element. This sort of trick might still be possible even if the link values were memory addresses rather than array indices, as many computers do not use their full word size for addressing.

The tree is represented via arrays NODE, LINKL and LINKR, initialised to the set example via some DATA statements rather than being built via a sequence of calls to something like ADDNODE. Old-style Fortran would require separate arrays, though one could mess about with two-dimensional arrays if the type of NODE was compatible. F90 and later enable the definition of compound data types, so that one might speak of NODE(i).CONTENT, NODE(i).LINKLEFT, and NODE(i).LINKRIGHT, or similar. While this offers clear benefits in organisation and documentation there can be surprises, as when a binary search routine was invoked on something like NODE(1:n).KEY and the programme ran a lot slower than the multi-array version! This was because rather than present the routine with an array having a "stride" other than one, the KEY values were copied from the data aggregate to a work area so that they were contiguous for the binary search routine, thereby vitiating its speed advantage over a linear search.

Except for the usage of array MIST having an element zero and the use of an array assignment MIST(:,0) = 0, the GORILLA code is old-style Fortran. One could play tricks with EQUIVALENCE statements to arrange that an array's first element was at index zero, but that would rely on the absence of array bound checking and is more difficult with multi-dimensional arrays. Instead, one would make do either by having a separate list length variable, or else remembering the offsets... The MODULE usage requires F90 or later and provides a convenient protocol for global data, otherwise one must mess about with COMMON or parameter hordes. If that were done, the B6700 compiler would have handled it. But for the benefit of trembling modern compilers it also contains the fearsome new attribute, RECURSIVE, to flog the compilers into what was formalised for Algol in 1960 and was available for free via Burroughs in the 1970s.

On the other hand, the early-style Fortran DO-loop would always execute once, because the test was made only at the end of an iteration, and here, routine JANE does not know the value of MAXLEVEL until after the first iteration. Code such as

DO GASP =1,MAXLEVELCALL TARZAN(1,HOW)ENDDO

Would not work with modern Fortran, because the usual approach is to calculate the iteration count from the DO-loop parameters at the start of the DO-loop, and possibly not execute it at all if that count is not positive. This also means that with each iteration, the count must be decremented and the index variable adjusted; extra effort. There is no equivalent of Pascal's Repeat ... until condition;, so, in place of a nice "structured" statement with clear interpretation, there is some messy code with a label and a GO TO, oh dear.

MODULE ARAUCARIA !Cunning crosswords, also.INTEGER ENUFF !To suit the set example.PARAMETER(ENUFF =9)!This will do.INTEGER NODE(ENUFF),LINKL(ENUFF),LINKR(ENUFF)!The nodes, and their links.DATA NODE/1,2,3,4,5,6,7,8,9/!Value = index. A rather boring payload.DATA LINKL/2,4,6,7,0,8,0,0,0/!"Left" and "Right" are as looking at the page.DATA LINKR/3,5,0,0,0,9,0,0,0/!If one thinks within the tree, they're the other way around!C 1 !Thus, looking from the "1", to the right is "2" and to the left is "3".C / \ !But, looking at the scheme, to the left is "2" and to the right is "3".C / \ !This latter seems to be the popular view from the outside, not within the data.C / \ !Similarily, although called a "tree", the depiction is upside down!C 2 3 !How can computers be expected to keep up with this contrariness?C / \ / !Humm, no example of a rightwards link with no leftwards link.C 4 5 6 !Topologically equivalent, but not so in usage.C / / \C 7 8 9INTEGER N,LIST(ENUFF)!This is to be developed.INTEGER LEVEL,MAXLEVEL !While these vary in various ways.INTEGER GASP !Communication from JANE.CONTAINS!No checks for invalid links, etc.SUBROUTINEOUT(IS)!Append a value to a list.INTEGER IS !The value. N = N +1!The list's count so far. LIST(N)= IS !Place.ENDSUBROUTINEOUT!Eventually, the list can be written in one go.

RECURSIVESUBROUTINE TARZAN(HAS,STYLE)!Skilled at tree traversal, is he.INTEGER HAS !The current position.CHARACTER*(*) STYLE !Traversal type. LEVEL = LEVEL +1!A leap is made.IF(LEVEL.GT.MAXLEVEL) MAXLEVEL = LEVEL !Staring at the moon.SELECTCASE(STYLE)!And, in what manner?CASE("PRE")!Declare the position first.CALLOUT(HAS)!Thus.IF(LINKL(HAS).GT.0)CALL TARZAN(LINKL(HAS),STYLE)IF(LINKR(HAS).GT.0)CALL TARZAN(LINKR(HAS),STYLE)CASE("IN")!Or in the middle.IF(LINKL(HAS).GT.0)CALL TARZAN(LINKL(HAS),STYLE)CALLOUT(HAS)!Thus.IF(LINKR(HAS).GT.0)CALL TARZAN(LINKR(HAS),STYLE)CASE("POST")!Or at the end.IF(LINKL(HAS).GT.0)CALL TARZAN(LINKL(HAS),STYLE)IF(LINKR(HAS).GT.0)CALL TARZAN(LINKR(HAS),STYLE)CALLOUT(HAS)!Thus.CASE("LEVEL")!Or at specified levels.IF(LEVEL.EQ.GASP)CALLOUT(HAS)!Such as this?IF(LINKL(HAS).GT.0)CALL TARZAN(LINKL(HAS),STYLE)IF(LINKR(HAS).GT.0)CALL TARZAN(LINKR(HAS),STYLE)CASEDEFAULT!This shouldn't happen. WRITE (6,*)"Unknown style ",STYLE !But, paranoia.STOP"No can do!"!Rather than flounder about.ENDSELECT!That was simple. LEVEL = LEVEL -1!Sag back.ENDSUBROUTINE TARZAN !Not like George of the Jungle.

SUBROUTINE JANE(HOW)!Tells Tarzan what to do.CHARACTER*(*) HOW !A single word suffices. N =0!No positions trampled. LEVEL =0!Starting on the ground. MAXLEVEL =0!The ascent follows.IF(HOW.NE."LEVEL")THEN!Ordinary styles?CALL TARZAN(1,HOW)!Yes. From the root, go...ELSE!But this is not tree-structured. GASP =0!Instead, we ascend through the canopy in stages.1 GASP = GASP +1!Up one stage.CALL TARZAN(1,HOW)!And do it all again.IF(GASP.LT.MAXLEVEL)GOTO1!Are we there yet?ENDIF!Don't know MAXLEVEL until after the first clamber.Cast forth the list. WRITE (6,10) HOW,NODE(LIST(1:N))!Show spoor.10 FORMAT (A6,"-order:",66(1X,I0))!Large enough. WRITE (6,*)!Sigh.ENDSUBROUTINE JANE !That was simple.ENDMODULE ARAUCARIA !The monkeys are puzzled.

Chase the links preorder style: name the node, delve its left link, delve its right link. N =0!No nodes have been visited. SP =0!My stack is empty. IT =1!I start at the root.10 N = N +1!Another node arrived at. LIST(N)= IT !Finger it.IF(LINKL(IT).GT.0)THEN!A left link?IF(LINKR(IT).GT.0)THEN!Yes. A right link also? SP = SP +1!Yes. Stack it up. STACK(SP)= LINKR(IT)!For later investigation.ENDIF!So much for the right link. IT = LINKL(IT)!Fingered by the left link.GOTO10!See what happens.ENDIF!But if there is no left link,IF(LINKR(IT).GT.0)THEN!There still might be a right link. IT = LINKR(IT)!There is.GOTO10!See what happens.ENDIF!And if there are no links,IF(SP.GT.0)THEN!Perhaps the stack has bottomed out too? IT = STACK(SP)!No, this was deferred. SP = SP -1!So, pick up where we left off.GOTO10!And carry on.ENDIF!So much for unstacking. WRITE (6,12)"Preorder",NODE(LIST(1:N))!I've got a little list!12 FORMAT (A12,":",66(1X,I0))CALL JANE("PRE")!Try it fancy style.

Chase the links inorder style: delve left fully, name the node and try its right, then unstack. N =0!No nodes have been visited. SP =0!My stack is empty. IT =1!I start at the root.20 SP = SP +1!I'm on the way down. STACK(SP)= IT !So, save this position to later retreat to.IF(LINKL(IT).GT.0)THEN!Can I delve further left? IT = LINKL(IT)!Yes.GOTO20!And see what happens.ENDIF!So much for diving.21IF(SP.GT.0)THEN!Can I retreat? IT = STACK(SP)!Yes. SP = SP -1!Go back to whence I had delved left. N = N +1!This now counts as a place in order. LIST(N)= IT !So list it.IF(LINKR(IT).GT.0)THEN!Have I a rightwards path? IT = LINKR(IT)!Yes. Take it.GOTO20!And delve therefrom.ENDIF!This node is now finished with.GOTO21!So, try for another retreat.ENDIF!So much for unstacking. WRITE (6,12)"Inorder",NODE(LIST(1:N))!I've got a little list!CALL JANE("IN")!Try with more style.

Chase the links postorder style: delve left fully, delve right, name the node, then unstack. N =0!No nodes have been visited. SP =0!My stack is empty. IT =1!I start at the root.30 SP = SP +1!Action follows delving, STACK(SP)= IT !So this node will be returned to.IF(LINKL(IT).GT.0)THEN!Take any leftwards link straightaway. IT = LINKL(IT)!Thus.GOTO30!Thanks to the stack, we'll return to IT (as was).ENDIF!But if there is no leftwards link to follow,IF(LINKR(IT).GT.0)THEN!Perhaps there is a rightwards one? STACK(SP)=-STACK(SP)!=-IT Mark the stacked finger as a rightwards lurch! IT = LINKR(IT)!The rightwards link is now to be taken.GOTO30!Thus start on a sub-tree.ENDIF!But if there is no rightwards link either,31IF(SP.GT.0)THEN!See if there is anywhere to retreat to. IT = STACK(SP)!The same IT placed at 30 if we dropped into 31. SP = SP -1!But now we're in a different mood.IF(IT.LT.0)THEN!Returning to what had been a rightwards departure? N = N +1!Yes! Then this node is post-interest. LIST(N)=-IT !So, time to roll it forth at last.GOTO31!And retreat some more.ENDIF!But if we hadn't gone right from IT,IF(LINKR(IT).LE.0)THEN!We had gone left. N = N +1!And now there is nowhere rightwards. LIST(N)= IT !So this node is post-interest.GOTO31!And retreat some more.ENDIF!But if there is a rightwards leap, SP = SP +1!Prepare to return to it, STACK(SP)=-IT !Marked as having gone rightwards. IT = LINKR(IT)!The rightwards move.GOTO30!Peruse a fresh sub-tree.ENDIF!And if the stack is reduced, WRITE (6,12)"Postorder",NODE(LIST(1:N))!Results!CALL JANE("POST")!The same again?

Chase the nodes level style. SP =0!My stack is empty. IT =1!I start at the root. LEVEL =0!On the ground. MAXLEVEL =0!No ascent as yet. MIST(:,0)=0!At all levels, nothing.40 LEVEL = LEVEL +1!Every arrival is one level up.IF(LEVEL.GT.MAXLEVEL) MAXLEVEL = LEVEL !Note the most high. MIST(LEVEL,0)= MIST(LEVEL,0)+1!The count at that level. MIST(LEVEL,MIST(LEVEL,0))= IT !Add to the level's list.IF(LINKL(IT).GT.0)THEN!Righto, can we go left?IF(LINKR(IT).GT.0)THEN!Yes. Rightwards as well? SP = SP +1!Yes! This will have to wait. STACK(SP)= LINKR(IT)!So remember it, SLEVL(SP)= LEVEL !And what level we're at now.ENDIF!I can only go one way at a time. IT = LINKL(IT)!Accept the fingered leftwards lurch.GOTO40!Go to IT.ENDIF!But if there is no leftwards link,IF(LINKR(IT).GT.0)THEN!Perhaps there is a rightwards one? IT = LINKR(IT)!There is.GOTO40!Go to IT.ENDIF!And if there are no further links,IF(SP.GT.0)THEN!Perhaps we can retreat to what was deferred. IT = STACK(SP)!The finger. LEVEL = SLEVL(SP)!The level. SP = SP -1!Wind back the stack.GOTO40!Go to IT.ENDIF!So much for the stack. WRITE (6,12)"Levelorder", !Roll the lists in ascending LEVEL order.1(NODE(MIST(LEVEL,1:MIST(LEVEL,0))), LEVEL =1,MAXLEVEL)CALL JANE("LEVEL")!Alternatively...END!So much for that.

post-order is not that much different from pre-order, except that the children must extracted before the parent.

postorder tree745289631

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 tree742518693

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 tree123456789

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. In all three cases, the parent value (m) for the node appears on the left, and the child tree(s) appear on the right. (And n must be parenthesized if it is not a single word.)

Of course, there are other ways of representing tree structures in J. One fairly natural approach pairs a list of data with a matching list of parent indices. For example:

example=:183475962,: 070838720

Here, we have two possible ways of identifying the root node. It can be in a known place in the list (index 0, for this example). But it is also the only node which is its own parent. For this task we'll use the more general (and thus slower) approach which allows us to place the root node anywhere in the sequence.

Here, data extracts the list of data items from the tree and parent extracts the structure from the tree.

depth examines the parent structure and returns the distance of each node from the root.

reorder is like indexing, except that it returns an equivalent tree (with the structural elements updated to maintain the original tree structure). The left argument for reorder should select the entire tree. Selecting partial trees is a more complex problem which needs specifications about how to deal with issues such as dangling roots and multiple roots. (Our abstraction here has no problem representing trees with multiple roots, but they are not relevant to this task.)

childinds extracts the child pointers which some of these results assume. This implementation assumes we are working with a binary tree (which is an explicit requirement of this task -- the parent node representation is far more general and can represent trees with any number of children at each node, but what would an "inorder" traversal look like with a trinary tree?).

Next, we define our "traversal" routines (actually, we are going a bit overboard here - we really only need to extract the data for this tasks's concept of traversal):

These routines assume that children of a node are arranged so that the lower index appears to the left of the higher index. If instead we wanted to rely on the ordering of their values, we could first use dataorder to enforce the assumption that child indexes are ordered properly.

checking that the tree is indeed binary, and returning undefined for the in-order traversal if any node in the tree has more than two children. (The other 3 traversals are still defined for rose trees).

// Recursively take any value found in the head node// of the remaining tail, deferring any child nodes// of that head to the end of the tailreturn lngTree ?( head ?([head.value].concat( levelOrder( tail .concat(head.nest||[])))): levelOrder(tail)):[];}

Copy of Euphoria.
This is included in the distribution as demo\rosetta\Tree_traversal.exw, which also contains a way to build such a nested structure, and thirdly a "flat list of nodes" tree, that allows more interesting options such as a tag sort.

procedure level_order(object tree, sequence more = {}) if sequence(tree) then more &= {tree[LEFT],tree[RIGHT]} printf(1,"%d ",{tree[VALUE]}) end if if length(more) > 0 then level_order(more[1],more[2..$]) end ifend procedure

/*********************************************************************** And now show the results and check them for correctness**********************************************************************/Call show 'inorder: ',il,il_soll

Exit

show: ParseArg Which,have,soll/*********************************************************************** Show our result and show it it's correct**********************************************************************/have=space(have)If have=soll Then tag=''Else tag='*wrong*'Say which have tagIf tag<>''ThenSay'------------>'soll 'is the expected result'Return

brother: ProcedureExpose node./*********************************************************************** Return the right node of this node's father or 0**********************************************************************/Parsearg no nof=node.no.0father brot1=node.nof.0riteReturn brot1

father: ProcedureExpose node./*********************************************************************** Return the father of the argument* or 0 if the root is given as argument**********************************************************************/ParseArg ndReturn node.nd.0father

lbot: ProcedureExpose node./*********************************************************************** From node z: Walk down on the left side until you reach the bottom* and return the bottom node* If z has no left son (at the bottom of the tree) returm itself**********************************************************************/ParseArg zDo i=1To100If node.z.0left<>0Then z=node.z.0leftElseLeaveEndReturn z

go_next: ProcedureExpose node. lvl/*********************************************************************** find the next node to visit in the treewalk**********************************************************************/ next=0Parsearg zIf node.z.0left<>0ThenDo/* there is a left son */If node.z.0left.done=0ThenDo/* we have not visited it */ next=node.z.0left /* so we go there */ node.z.0left.done=1/* note we were here */ lvl=lvl+1/* increase the level */EndEndIf next=0ThenDo/* not moved yet */If node.z.0rite<>0ThenDo/* there is a right son */If node.z.0rite.done=0ThenDo/* we have not visited it */ next=node.z.0rite /* so we go there */ node.z.0rite.done=1/* note we were here */ lvl=lvl+1/* increase the level */EndEndEndIf next=0ThenDo/* not moved yet */ next=node.z.0father /* go to the father */ lvl=lvl-1/* decrease the level */EndReturn next /* that's the next node *//* or zero if we are done */

attleft: ProcedureExpose node./*********************************************************************** make son the left son of father**********************************************************************/ParseArg son,father node.son.0father=father z=node.father.0leftIf z<>0ThenDo node.z.0father=son node.son.0left=zEnd node.father.0left=sonReturn

attrite: ProcedureExpose node./*********************************************************************** make son the right son of father**********************************************************************/ParseArg son,father node.son.0father=father z=node.father.0riteIf z<>0ThenDo node.z.0father=son node.son.0rite=zEnd node.father.0rite=son le=node.father.0leftIf le>0Then node.le.0brother=node.father.0riteReturn

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.

Ursala has built-in notation for trees and is perfect for whipping up little
tree walking functions. This source listing shows the tree depicted above
declared as a constant, followed by declarations of four functions
applicable to trees of any type. The main program applies all four of them
to the tree and makes a list of their results, each of which is a list of
natural numbers. The compiler directive #cast %nLL induces the compile-time
side effect of displaying
the result on standard output as a
list of lists of naturals.