# 1
VBA Recursion
VBA Recursion
What is the “base case”?
What is the programming stack?
CS 105 Spring 2010
# 2
Recursive procedures are defined in terms of themselves; e.g., a function is recursive if it contains calls back to itself or to another function that calls the original function.
Recursive programming usually requires more memory and runs more slowly than non-recursive programs. This is due to the cost of implementing the “stack”.
However, recursion is often a natural way to define a problem.
Recursive Procedures
# 3
1. Problem DefinitionWrite a factorial function. 0! = 1 and n! = n*(n-1)!. Use “recursion” to implement the factorial function.
2. Refine, Generalize, Decompose the problem definition(i.e., identify sub-problems, I/O, etc.)Input = Non-negative integers as input.Output= return the factorial of the input value. Note: that 69! = 1.711224524... x 1098
so our function will only work for small integer values.
Example: Factorial FunctionExample: Factorial Function
# 4
Function fact(intN As Integer) As Integer
If intN = 0 Then ' base case fact = 1 Else fact = intN * fact(intN - 1) 'recursive call End If
End Function
Example: Factorial FunctionExample: Factorial Function
# 5
(push) fact = 3 * fact(3 - 1) (intN = 3)
(push) fact = 2 * fact(2 - 1) (intN = 2)
(push) fact = 1 * fact(0) (intN = 1)
(push/pop) fact = 1 (intN = 0)
(pop) fact = 1 * 1 (intN = 1)
(pop) fact = 2 * 1 (intN = 2)
(pop) fact = 3 * 2 (intN = 3)
fact = 1 (intN = 0) fact = 1 * fact(0) (intN = 1) fact = 2 * fact(2- 1) (intN = 2) fact = 3 * fact(3- 1) (intN = 3)
(STACK)
The “stack” contains “stack frames”
fact = 1 * 1 (intN = 1) fact = 2 * fact(2- 1) (intN = 2) fact = 3 * fact(3- 1) (intN = 3)
fact = 2 * 1 (intN = 2) fact = 3 * fact(3- 1) (intN = 3)
(empty)
fact = 3 * 2 (intN = 3)
# 6
1. Problem DefinitionWrite a solve_maze function. We assume that a maze has been created in the range A1:J10. Write a Subprocedure to display one path that traverses the maze. Use “recursion” to implement the maze subprocedure.
2. Refine, Generalize, Decompose the problem definition(i.e., identify sub-problems, I/O, etc.)Input = The maze in the range A1:J10
Your program will have to find its way through a 10x10 maze where the symbols “ * ” , “O” and “X” denote:
“ * ” are solid walls through which you cannot travel"O" denotes the starting position, "X" is the exit for which you are looking for
Example: Traversing a MazeExample: Traversing a Maze
# 7
* * * * * * * * * ** ** * * * * * O ** * * * ** * * X ** * * * * * ** * ** * * * * * ** * ** * * * * * * * * *
# 8
2. Refine, Generalize, Decompose the problem definitionInput (continued): Read the maze into the 2D array,
*********** ***** * *O* * * **** * *X** ** *** ** * ** *** ** ** * ***********
Dim strMaze(1 to 10, 1 to 10) as String
The upper left-hand corner of the maze has the value strMaze(1,1) . If we want to test whether the cell in thefourth row and fourth column contains a wall then it's enough to use an if statement like this:
if (strMaze(4,4) = “ * “)
Example: Traversing a MazeExample: Traversing a Maze
# 9
2. Refine, Generalize, Decompose the problem definitionOutput : Display a solution as follows:
Example: Traversing a MazeExample: Traversing a Maze
# 10
3. Develop Algorithm
(processing steps to solve problem)
Step 1 Read in the “maze” and find the starting Row and Column (the position of the “O”).
Use variables “intRow” and “intCol” to keep track of the current position as we traverse through the maze (the 2D matrix strMaze).
Step 2 Display the maze.
Step 3 Check to see if current position is an “X” then we are done. Otherwise first try to go up and if not then down and if not then left and if not then right and if you can go up/down/left/right then go back to Step 2. Otherwise, go back to the previous position (intRow,intCol) and try another direction.
Example: Traversing a MazeExample: Traversing a Maze
# 11
Private Sub cmdSolve_Click()
Dim strMaze(1 To 10, 1 To 10) As String
Dim intRow As Integer, intCol As Integer
Dim intStartRow As Integer, intStartCol As Integer
' Read the maze into strMaze and
' find intStartRow, intStartCol
For intRow = 1 To 10
For intCol = 1 To 10
strMaze(intRow, intCol) = Cells(intRow, intCol).Value
If strMaze(intRow, intCol) = "O" Then
intStartRow = intRow
intStartCol = intCol
End If
Next intCol
Next intRow
' SolvMaze is a recursive subprocedure
SolveMaze strMaze, intStartRow, intStartCol
End Sub
# 12
Sub SolveMaze(strMaze() As String, intRow As Integer, intCol As Integer)
'Draw the maze
DrawMaze strMaze, 10, 10
'Check if solution found.
If strMaze(intRow - 1, intCol) = "X" Or _
strMaze(intRow + 1, intCol) = "X" Or _
strMaze(intRow, intCol + 1) = "X" Or _
strMaze(intRow, intCol - 1) = "X" Then
End 'End terminates ALL recursive calls
End If
' Recurse in each possible direction that is empty.
'Move up
If strMaze(intRow - 1, intCol) = "" Then
strMaze(intRow - 1, intCol) = "O"
SolveMaze strMaze, intRow - 1, intCol
strMaze(intRow - 1, intCol) = "“
DrawMaze strMaze, 10, 10
End If
' continued on next slide
# 13
'Move down
If strMaze(intRow + 1, intCol) = "" Then
strMaze(intRow + 1, intCol) = "O"
SolveMaze strMaze, intRow + 1, intCol
strMaze(intRow + 1, intCol) = "“
DrawMaze strMaze, 10, 10
End If
'Move left
If strMaze(intRow, intCol - 1) = "" Then
strMaze(intRow, intCol - 1) = "O"
SolveMaze strMaze, intRow, intCol - 1
strMaze(intRow, intCol - 1) = "“
DrawMaze strMaze, 10, 10
End If
'Move right
If strMaze(intRow, intCol + 1) = "" Then
strMaze(intRow, intCol + 1) = "O"
SolveMaze strMaze, intRow, intCol + 1
strMaze(intRow, intCol + 1) = "“
DrawMaze strMaze, 10, 10
End IfEnd Sub
# 14
Sub DrawMaze(strMaze() As String, intRows As Integer, intCols As Integer)
Dim intRow As Integer, intCol As Integer
For intRow = 1 To intRows
For intCol = 1 To intCols
Cells(intRow, intCol).Value = strMaze(intRow, intCol)
Next intCol
Next intRow
Pause 0.4
End Sub
Sub Pause(sngTime As Single)
Dim sngStart As Single
sngStart = Timer ' Set start time.
Do While Timer < sngStart + sngTime
DoEvents
Loop
End Sub
# 15
According to legend, in the great temple of Benares, beneath the dome which marks the center of the world, rests a brass plate on which are fixed three diamond needles. On one of these needles at creation, there were placed 64 discs of pure gold, the largest disc resting on the brass plate and the others getting smaller up to the top one. This is the TOWERS OF HANOI. Day and night, the people on duty move the discs from one needle to another, according to the two following laws:
Law 1: Only one disc at a time may be moved.
Law 2: A larger disc may never rest on a smaller disc.
The workers labor in the belief that once the tower has been transferred to another needle there will be heaven on earth, so they want to complete the task in the least number of moves.
Example: Towers of HanoiExample: Towers of Hanoi
# 16
Actually, the Tower of Hanoi puzzle was invented in 1883 by the French mathematician Edouard Lucas (1842-1891), who made up the legend to accompany it.
Example: Towers of HanoiExample: Towers of Hanoi
# 17
An elegant and efficient way to solve this problem is to think recursively.
Suppose that you, somehow or other, have found the most efficient way possible to transfer a tower of n-1 disks one by one from one pole to another obeying the restriction that you never place a larger disk on top of a smaller one. Then, what is the most efficient way to move a tower of n disks from one pole to another?
Example: Towers of HanoiExample: Towers of Hanoi
# 18
Assume we know how to move n-1 disks from one peg to another.Then can we move n disks from peg 1 to peg 3 ?
1. Move n-1 disks from peg 1 to peg 2, peg 3 is just a temporary holding area
2. Move the last disk(the largest) from peg 1 to peg 3
3. Move the n-1 disks from peg 2 to peg 3, peg 1 is just a temporary holding area.
1 2 3
n disks
Pseudo-codePseudo-code
# 20
Private Sub cmdTower_Click()
mintNumDisks = InputBox("How many disks?", "Tower of Hanoi", 8)
' draw the tower
DrawTower
' call recursive subprocedure, hanoi
' peg 1 is the origin, peg 3 is the destination and
' peg 2 is the spare
Hanoi 1, 3, 2, mintNumDisks
End Sub
Towers of HanoiTowers of Hanoi
# 21
Sub Hanoi(intOrigin As Integer, intDestination As Integer, intSpare As Integer, _ intNumDisks As Integer)
If intNumDisks = 1 Then
' move top disk on peg intOrigin to peg intDestination
Pause 0.6
MoveDisks intOrigin, intDestination
Else
' peg intOrigin is the origin, peg intSpare is the
' destination and peg intNumDisks is the spare
Hanoi intOrigin, intSpare, intDestination, intNumDisks - 1
' move top disk on peg intOrigin to peg intDestination
Pause 0.6
MoveDisks intOrigin, intDestination
Hanoi intSpare, intDestination, intOrigin, intNumDisks - 1
End If
End Sub
# 22
Going back to the legend, suppose the workers rapidly move one disk every second. As shown earlier, the minimum sequence of moves must be :
The minimum number of moves needed to transfer a tower of n disks from peg1 to peg3
The minimum number of moves needed to transfer n-1 disks from peg1 to peg2
The minimum number of movesneeded to transfer the n th disk from peg1 to peg3
The minimum number of moves needed to transfer n-1 disks from peg2 to peg3 on top of the n th disk
Therefore, the recurrence relation is moves(n) = 2*moves(n-1) + 1 and initial case is moves(1) = 1 second. For example, moves(2) = 2*moves(1) + 1 = 3,moves(3) = 2*moves(2) + 1 = 7, or in general,moves(n) = 2n-1Then, the time to move all 64 disks from one peg to the other, and end the universe would be moves(64) seconds or 584.9 billion years!!
= + +
Computational ComplexityComputational Complexity