Before I begin, a disclaimer: I realize that this is somewhat of an obscure topic. Your computer science majors should know what recursion is, but I doubt that many non-comp. sci. majors do. Furthermore, I will be showing an example of recursion on Microsoft's TreeView control, a control many ASP developers are not familiar with (unless they're VB developers as well), although, just so you know, you can use the TreeView Control as an ActiveX control on your web pages. This article will first discuss the basics of recursion and why it is powerful. Next, a simple, classic recursion problem will be demonstrated (finding factorials), and then I will show you how to visit all nodes in a TreeView Control.
What is Recursion?
I'm glad you asked. Recursion is repeatedly calling the same function to provide some meaningful output; at least that's what a computer scientist will tell you. A more mathematical definition of recursion is plugging in some start values into a function, getting the function's results, and reapplying them to the orginal function. Recursive functions often have odd sounding explanations. A factorial can be explaned in recursive terms. (In case you don't know, the factorial of n, written n!, is n*(n-1)*(n-2)*...*(n-(n-1)). So, 5! (pronounced five factorial) is equal to 5*4*3*2*1, or 120.
A factorial can be defined recursively as follows:
Start out with some natural number N (in our example, 5)
The factorial of N is N * the factorial of N-1.
So, if we let N be 5, then 5! is 5*4!. Now, we "recurse", letting N be 4. So 4! is 4*3!. So 5! = 5*4*3!. (I know most are probably lost now. We started out with 5 factorial, and then let 5 factorial equal 5*4 factorial. We then let 5 factorial equal 5*4*3 factorial, by repeatedly applying the recursive definition of factorial.) So, 3! is 3*2!, 2! is 2*1!, 1! is 1*0!, and 0! is defined to equal 1. So,
5! = 5*4! = 5*4*3! = 5*4*3*2! = 5*4*3*2*1! = 5*4*3*2*1*0! = 5*4*3*2*1*1
which, lo an behold, equals 120. We applied the recursive definition of a factorial to go from 5! to 120.
Now you may be wondering how in the world you write code to do this. Well, you simply write a function that will call itself. Here is the factorial function in VBScript:
function factorial(N) if N = 0 then factorial = 1 exit function end if factorial = N * factorial(N-1) end function
If you were to do:
Your output would be: 120. The above function has all of the same rules that our mathematical recursive definition of a factorial did. We define 0! to equal 1, and we define factorial N (where N > 0), to be N * factorial(N-1). All recursive functions must have an exit condition, that is a state when it does not recurse upon itself. Our exit condition in this example is when N=0. If you do not have an exit condition, you're recursive function will recurse forever until you run out of stack space. To make a long story short, you'll receive some nasty error about lack of memory, or stack overflow.
You're probably wondering what is really happening in the code. You can see if you trace the flow of the function through. It can be difficult at times, but you must be able to do this to fully understand recursion.
When the factorial function is first called with, say, N = 5, here is what happens:
Does N = 0? No
Function Return Value = 5 * FACTORIAL(4)
At this time, the function factorial is called again, with N = 4.
Does N = 0? No
Function Return Value = 4 * FACTORIAL(3)
At this time, the function factorial is called again, with N = 3.
Does N = 0? No
Function Return Value = 3 * FACTORIAL(2)
At this time, the function factorial is called again, with N = 2.
Does N = 0? No
Function Return Value = 2 * FACTORIAL(1)
At this time, the function factorial is called again, with N = 1.
Does N = 0? No
Function Return Value = 1 * FACTORIAL(0)
At this time, the function factorial is called again, with N = 0.
Does N = 0? Yes
Function Return Value = 1
Now, we have to trace our way back up! See, the factorial function was called six times. At any function level call, all function level calls above still exist! So, when we have N = 2, the function instances where N = 3, 4, and 5 are still waiting for their return values.
So, the function call where N = 1 gets retraced first, once the final guy returns 0. So, the function call where N = 1 returns 1*1, or 1. The next higher function call, where N = 2, returns 2 * 1 (1, because that's what the function call where N = 1 returned). You just keep working up the chain.
Where N = 2, 2*1, or 2 was returned
Where N = 3, 3*2, or 6 was returned
Where N = 4, 4*6, or 24 was returned
Where N = 5, 5*24, or 120 was returned
And since N = 5 was the first function call (hence the last one to be recalled), the value 120 is returned.
I hope you are still with me. Recursion is a tricky subject, but an important and powerful one. I will now show how to recurse through ALL the children in a TreeView structure.
A TreeView Control is a hierarchy. There are an undetermined number of levels in the hierarchy, and each node in the hierarchy can have zero or more children on the next lower level of the hierarchy. Microsoft provides an example script of how to list all of the children of a particular node at http://msdn.microsoft.com/library/devprods/vs6/vb/html/vbprochildrenx.htm. However, if you want to visit every single node, then you need to use recursion (well, technically you don't need to, but it's an easy way to make sure to visit every node).
Without further ado, here's the script:
sub TraverseTree(strKey) Dim iIndex if parent.frames(0).tv.Nodes(strKey).Children > 0 then 'We have children, we need to iterate through our children iIndex = parent.frames(0).tv.Nodes(strKey).Child.Index TraverseTree(parent.frames(0).tv.Nodes(iIndex).Key) While iIndex <> parent.frames(0).tv.Nodes(strKey).Child.LastSibling.Index iIndex = parent.frames(0).tv.Nodes(iIndex).Next.Index TraverseTree(parent.frames(0).tv.Nodes(iIndex).Key) Wend end if 'Here is where you will want to put whatever processing you want done 'on each and every node. end sub
This function is called by passing in the Key of the node that you want to start at. It won't neccessarily visit all of the nodes in the tree, but will visit all of the children of the node's Key you pass in (including the passed in node as well). To reiterate, Microsoft's script will visit all of the direct children of a given node; the above script will visit ALL descendants of a given node (including the given node).
Well, I hope I didn't confuse too many of you, and I hope you found this to be an interesting topic! I know I do! :)