{"id":287,"date":"2023-08-14T01:08:06","date_gmt":"2023-08-14T01:08:06","guid":{"rendered":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/?post_type=chapter&#038;p=287"},"modified":"2023-10-22T14:56:12","modified_gmt":"2023-10-22T14:56:12","slug":"recursion","status":"publish","type":"chapter","link":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/chapter\/recursion\/","title":{"raw":"Recursion","rendered":"Recursion"},"content":{"raw":"<div class=\"textbox textbox--learning-objectives\"><header class=\"textbox__header\">\r\n<p class=\"textbox__title\">Learning Objectives<\/p>\r\n\r\n<\/header>\r\n<div class=\"textbox__content\">\r\n<p class=\"import-Normal\">After reading this chapter you will\u2026<\/p>\r\n\r\n<ul>\r\n \t<li class=\"import-Normal\">understand the features of recursion and recursive processes.<\/li>\r\n \t<li class=\"import-Normal\">be able to identify the components of a recursive algorithm.<\/li>\r\n \t<li class=\"import-Normal\">be able to implement some well-known recursive algorithms.<\/li>\r\n \t<li class=\"import-Normal\">be able to estimate the complexity of recursive processes.<\/li>\r\n \t<li class=\"import-Normal\">understand the benefits of recursion as a problem-solving strategy.<\/li>\r\n<\/ul>\r\n<\/div>\r\n<\/div>\r\n<h1 class=\"import-Normal\">Introduction<\/h1>\r\n<p class=\"import-Normal\">Recursion is a powerful tool for computation that often saves the programmer considerable work. As you will see, the benefit of recursion lies in its ability to simplify the code of algorithms, but first we want to better understand recursion. Let\u2019s look at a simple nonrecursive function to calculate the product of 2 times a nonnegative integer, n, by repeated addition:<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image5.png\" alt=\"image\" width=\"618px\" height=\"86.262467191601px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This function takes a number, n, as an input parameter and then defines a procedure to repeatedly add 2 to a sum. This approach to calculation uses a for-loop explicitly. Such an approach is sometimes referred to as an iterative process. This means that the calculation repeatedly modifies a fixed number of variables that change the current \u201cstate\u201d of the calculation. Each pass of the loop updates these state variables, and they evolve toward the correct value. Imagine how this process will evolve as a computer executes the function call <strong>multiplyBy2(3)<\/strong>. A \u201ccall\u201d asks the computer to evaluate the function by executing its code.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">When the process starts, <strong>sum<\/strong> is 0. Then the process iteratively adds 2 to the <strong>sum<\/strong>. The process generated is equivalent to the mathematical expression (2 + 2 + 2). The following table shows the value of each variable (<strong>i<\/strong>, <strong>sum<\/strong>, and <strong>n<\/strong>) at each time step:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n\r\n<img class=\"aligncenter wp-image-861 \" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/2.1.png\" alt=\"A table showing how multiplication can be performed using successive addition of a non-negative value.\" width=\"529\" height=\"191\" \/>\r\n<p class=\"import-Normal\">Figure 2.1<\/p>\r\n\r\n<\/div>\r\n<h2 class=\"import-Normal\">Recursive Multiplication<\/h2>\r\n<p class=\"import-Normal\">Like iterative procedures, recursive procedures are a means to repeat certain operations in code. We will now write a recursive function to calculate the multiplication by 2 as a sequence of addition operations.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image6-1.png\" alt=\"image\" width=\"616px\" height=\"85.9833070866142px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The recursive formulation follows the mathematical intuition that 2 * n = 2 + 2 * (n \u2212 1) = 2 + 2 + 2 * (n \u2212 2) \u2026 and so on until you reach 2 + 2 + 2 + \u2026 2 * 1. We can visualize this process by considering how a computer might evaluate the function call <strong>recursiveMultiplyBy2(3)<\/strong>. The evaluation process is similar conceptually to a rewriting process.<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 36pt; margin-right: 36pt;\">recursiveMultiplyBy2(3) -&gt; 2 + recursiveMultiplyBy2(2)<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 + 2 + recursiveMultiplyBy2(1)<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 + 2 + 2 + recursiveMultiplyBy2(0)<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 + 2 + 2 + 0<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 + 2 + 2<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 6<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This example demonstrates a few features of a recursive procedure. Perhaps the most recognizable feature is that it makes a call to itself. We can see that <strong>recursiveMultiplyBy2<\/strong> makes a call to <strong>recursiveMultiplyBy2<\/strong> in the else part of the procedure. As an informal definition, a recursive procedure is one that calls to itself (either directly or indirectly). Another feature of this recursive procedure is that the action of the process is broken into two parts. The first part directs the procedure to return 0 when the input, n, is equal to 0. The second part addresses the other case where n is not 0. We now have some understanding of the features of all recursive procedures.<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 0pt; text-indent: 0pt;\">Features of Recursive Procedures<\/p>\r\n\r\n<ul>\r\n \t<li class=\"import-Normal\" style=\"text-indent: 0pt;\">A recursive procedure makes reference to itself as a procedure. This self-call is known as the recursive call.<\/li>\r\n \t<li class=\"import-Normal\" style=\"text-indent: 0pt;\">Recursive procedures divide work into two cases based on the value of their inputs.\r\n<ul>\r\n \t<li class=\"import-Normal\" style=\"text-indent: 0pt;\">One case is known as the base case.<\/li>\r\n \t<li class=\"import-Normal\" style=\"text-indent: 0pt;\">The other case is known as the recursive case or sometimes the general case.<\/li>\r\n<\/ul>\r\n<\/li>\r\n<\/ul>\r\n<h2 class=\"import-Normal\">Recursive Exponentiation<\/h2>\r\n<p class=\"import-Normal\">Let us now consider another example. Just as multiplication can be modeled as repeated addition, exponentiation can be modeled as repeated multiplication. Suppose we wanted to modify our iterative procedure for multiplying by 2 to create an iterative procedure for calculating powers of 2 for any nonnegative integer n. How might we modify our procedure? We might simply change the operation from + (add) to * (multiply).<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image7.png\" alt=\"image\" width=\"623.283569553806px\" height=\"87px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This procedure calculates a power of 2 for any nonnegative integer n. We changed not only the operation but also the starting value from 0 to 1.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">We can also write this procedure recursively, but first let us think about how to formulate this mathematically by looking at an example. Suppose we want to calculate 2<sup>3<\/sup>:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">2<sup>3<\/sup>=2 * 2<sup>2<\/sup><\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=2 * 2 * 2<sup>1<\/sup><\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=2 * 2 * 2 * 2<sup>0<\/sup><\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=2 * 2 * 2 * 1=8.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The explicit 2<sup>0<\/sup> is shown to help us think about the recursive and base cases. From this example, we can formulate two general rules about exponentiation using 2 as the base:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">2<sup>0<\/sup>=1<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">2<sup>n<\/sup>=2 * 2<sup>(n\u22121)<\/sup>.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Now let\u2019s write the recursive procedure for this function. Try to write this on your own before looking at the solution.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image8-1.png\" alt=\"image\" width=\"620px\" height=\"86.5416272965879px\" \/><\/p>\r\n\r\n<h1 class=\"import-Normal\">The Structure of Recursive Algorithms<\/h1>\r\n<p class=\"import-Normal\">As mentioned above, recursive procedures have a certain structure that relies on self-reference and splitting the input into cases based on its value. Here we will discuss the structure of recursive procedures and give some background on the motivation for recursion.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Before we begin, recall from chapter 1 that a procedure can be thought of as a specific implementation of an algorithm. While these are indeed two separate concepts, they can often be used interchangeably when considering pseudocode. This is because the use of an algorithm in practice should be made as simple as possible. Often this is accomplished by wrapping the algorithm in a simple procedure. This design simplifies the interface, allowing the programmer to easily use the algorithm in some other software context such as a program or application. In this chapter, you can treat algorithm and procedure as the same idea.<\/p>\r\n\r\n<h2 class=\"import-Normal\">Some Background on Recursion<\/h2>\r\n<p class=\"import-Normal\">The concept of recursion originated in the realm of mathematics. It was found that some interesting mathematical sequences could be defined in terms of themselves, which greatly simplified their definitions. Take for example the Fibonacci sequence:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, \u2026 }.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This sequence is likely familiar to you. The sequence starts at 0, 0 is followed by 1, and each subsequent value in the sequence is derived from the previous two elements in the sequence. This seemingly simple sequence is fairly difficult to define in an explicit way. Let\u2019s look a bit closer.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Based on the sequence above, we see the following equations are true:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>0<\/sub> = 0<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>1<\/sub> = 1<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>2<\/sub> = 1<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>3<\/sub> = 2<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>4<\/sub> = 3.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Using this formulation, we may wish to find a function that would calculate the nth Fibonacci number given any positive integer, n:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">F<sub>n<\/sub> = ?.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Finding such a function that depends only on n is not trivial. This also leads to some difficulties in formally defining the sequence. To partially address this issue, we can use a recursive definition. This allows the sequence to be specified using a set of simple rules that are self-referential in nature. These recursive rules are referred to in mathematics as recurrence relations. Let\u2019s look at the recurrence relation for the Fibonacci sequence:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>0<\/sub>=0<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>1<\/sub>=1<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>n<\/sub>=F<sub>n\u22121<\/sub> + F<sub>n\u22122<\/sub>.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This gives a simple and perfectly correct definition of the sequence, and we can calculate the nth Fibonacci number for any positive integer n. Suppose we wish to calculate the eighth Fibonacci number. We can apply the definition and then repeatedly apply it until we reach the F<sub>0<\/sub> and F<sub>1<\/sub> cases that are explicitly defined:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>8<\/sub>=F<sub>8\u22121<\/sub> + F<sub>8\u22122<\/sub><\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=F<sub>7<\/sub> + F<sub>6<\/sub><\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=(F<sub>7\u22121<\/sub> + F<sub>7\u22122<\/sub>) + (F<sub>6\u22121<\/sub> + F<sub>6\u22122<\/sub>)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">\u2026and so on.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\">This may be a long process if we are doing this by hand. This could be an especially long process if we fail to notice that F<sub>7\u22122<\/sub> is the same as F<sub>6\u22121<\/sub>.<\/p>\r\n\r\n<h2 class=\"import-Normal\">A Trade-Off with Recursion<\/h2>\r\n<p class=\"import-Normal\">Observing this process leads us to another critical insight about recursive processes. What may be simple to describe may not be efficient to calculate. This is one of the major drawbacks of recursion in computing. You may be able to easily specify a correct algorithm using recursion in your code, but that implementation may be wildly inefficient. Recursive algorithms can usually be rewritten to be more efficient. Unfortunately, the efficiency of the implementation comes with the cost of losing the simplicity of the recursive code. Sacrificing simplicity leads to a more difficult implementation. Difficult implementations allow for more bugs.<\/p>\r\n\r\n<h2 class=\"import-Normal\">An Aside on Navigating the Efficiency-Simplicity Trade-Off<\/h2>\r\n<p class=\"import-Normal\">In considering the trade-off between efficiency and simplicity, context is important, and there is no \u201cright\u201d answer. A good guideline is to focus on correct implementations first and optimize when there is a problem (verified by empirical tests). Donald Knuth references Tony Hoare as saying \u201cpremature optimization is the root of all evil\u201d in programming. This should not be used as an excuse to write inefficient code. It takes time to write efficient code. \u201cI was optimizing the code\u201d is a poor excuse for missed deadlines. Make sure the payoff justifies the effort.<\/p>\r\n\r\n<h2 class=\"import-Normal\">Recursive Structure<\/h2>\r\n<p class=\"import-Normal\">The recursive definition of the Fibonacci sequence can be divided into two parts. The first two equations establish the first two values of the sequence explicitly by definition for n = 0 and n = 1. The last equation defines Fibonacci values in the general case for any integer n &gt; 1. The last equation uses recursion to simplify the general case. Let\u2019s rewrite this definition and label the different parts.<\/p>\r\n\r\n<h1 class=\"import-Normal\">Base Cases<\/h1>\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>0<\/sub> = 0<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>1<\/sub> = 1<\/p>\r\n\r\n<\/div>\r\n<h1 class=\"import-Normal\">Recursive Case<\/h1>\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">F<sub>n<\/sub> = F<sub>n\u22121<\/sub> + F<sub>n\u22122<\/sub><\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\">Recursive algorithms have a similar structure. A recursive procedure is designed using the base case (or base cases) and a recursive case. The base cases may be used to explicitly define the output of a calculation, or they may be used to signal the end of a recursive process and stop the repeated execution of a procedure. The recursive case makes a call to the function itself to solve a portion of the original problem. This is the general structure of a recursive algorithm. Let\u2019s use these ideas to formulate a simple algorithm to calculate the nth Fibonacci number. Before we begin, let\u2019s write the cases we need to consider.<\/p>\r\n\r\n<h1 class=\"import-Normal\">Base Cases<\/h1>\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">n = 0 the algorithm should return 0<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">n = 1 the algorithm should return 1<\/p>\r\n\r\n<\/div>\r\n<h1 class=\"import-Normal\">Recursive Case<\/h1>\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">any other n the algorithm returns the sum of Fibonacci(n \u2212 1) and Fibonacci(n \u2212 2)<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\">Now we define the recursive algorithm to calculate the nth Fibonacci number.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image9-1.png\" alt=\"image\" width=\"618.731338582677px\" height=\"116.01217847769px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">In this algorithm, conditional if-statements are used to select the appropriate action based on the input value of n. If the value is 0 or 1, the input is handled by a base case, and the function directly returns the appropriate value. If another integer is input, the recursive case handles the calculation, and two more calls to the procedure are executed. You may be thinking, \u201cWait, for every function call, it calls itself two more times? That doesn\u2019t sound efficient.\u201d You would be right. This is not an efficient way to calculate the Fibonacci numbers. We will revisit this idea in more detail later in the chapter.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Before we move on, let us revisit the two examples from the introduction, multiplication and exponentiation. We can define these concepts using recurrence relations too. We will use the generic letter a for these definitions.<\/p>\r\n\r\n<h3 class=\"import-Normal\">Multiplication by 2<\/h3>\r\n<h1 class=\"import-Normal\">Base Case<\/h1>\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">a<sub>0<\/sub> = 0<\/p>\r\n\r\n<\/div>\r\n<h1 class=\"import-Normal\">Recursive Case<\/h1>\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">a<sub>n<\/sub> = 2 + a<sub>n\u22121<\/sub><\/p>\r\n\r\n<\/div>\r\n<h3 class=\"import-Normal\">Powers of 2<\/h3>\r\n<h1 class=\"import-Normal\">Base Case<\/h1>\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">a<sub>0<\/sub> = 1<\/p>\r\n\r\n<\/div>\r\n<h1 class=\"import-Normal\">Recursive Case<\/h1>\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">a<sub>n<\/sub> = 2 * a<sub>n\u22121<\/sub><\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\">Looking back at the recursive functions for these algorithms, we see they have a shared structure that uses conditionals to select the correct case based on the input, and the base cases and recursive cases handle the calculation by ending the chain of recursive calls or by adding to the chain of calls respectively. In the next section, we will examine some important details of how a computer executes these function definitions as dynamic processes to generate the correct result of a calculation.<\/p>\r\n\r\n<h1 class=\"import-Normal\">Recursion and the Runtime Stack<\/h1>\r\n<p class=\"import-Normal\">Thus far, we have relied on your intuitive understanding of how a computer executes function calls. Unless you have taken a computer organization or assembly language course, this process may seem a little mysterious. How does the computer execute the same procedure and distinguish the call to <strong>recursiveMultiplyBy2(3)<\/strong> from the call to <strong>recursiveMultiplyBy2(2)<\/strong> that arises from the previous function call? Both calls utilize the same definition, but one has the value 3 bound to <strong>n<\/strong> and the other has the value 2 bound to <strong>n<\/strong>. Furthermore, the result of <strong>recursiveMultiplyBy2(2)<\/strong> is needed by the call to <strong>recursiveMultiplyBy2(3)<\/strong> before a value may be returned. This requires that a separate value of n needs to be stored in memory for each execution of the function during the evaluation process. Most modern computing systems utilize what is known as a runtime stack to solve this problem.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">A stack is a simple data structure where data are placed on the top and removed from the top. Like a stack of books, to get to a book in the middle, one must first remove the books on top. We will address stacks in more detail in a later chapter, but we will briefly introduce the topic. Here we will examine how a runtime stack is used to store the necessary data for the execution of a recursive evaluation process.<\/p>\r\n\r\n<h2 class=\"import-Normal\">The Runtime Stack<\/h2>\r\n<p class=\"import-Normal\">We will give a rough description of the runtime stack. This should be taken as a cartoon version or caricature of the actual runtime stack. We encourage you to supplement your understanding of this topic by exploring some resources on computer organization and assembly language. The real-world details of computer systems can be as important as the abstract view presented here.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The runtime stack is a section of memory that stores data associated with the dynamic execution of many function calls. When a function is called at runtime, all the data associated with that function call, including input arguments and locally defined variables, are placed on the stack. This is known as \u201cpushing\u201d to the stack. The data that was pushed onto the stack represents the state of the function call as it is executing. You can think of this as the function\u2019s local environment during execution. We call this data stored on the stack a <strong>stack frame<\/strong>. The stack frame is a contiguous section of the stack that is associated with a specific call to a procedure. There may be many separate stack frames for the same procedure. This is the case with recursion, where the same function is called many times with distinct inputs.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Once the execution of a function completes, its data are no longer needed. At the time of completion, the function\u2019s data are removed from the top of the stack or \u201cpopped.\u201d Popping data from the runtime stack frees it, in a sense, and allows that memory to be used for other function calls that may happen later in the program execution. As the final two steps in the execution of the procedure, the function\u2019s stack frame is popped, and its return value (if the function returns a value) is passed to the caller of the function. The calling function may be a \u201cmain\u201d procedure that is driving the program, or it may be another call to the same function as in recursion. This allows the calling function to proceed with its execution. Let\u2019s trace a simple recursive algorithm to better understand this process.<\/p>\r\n\r\n<h2 class=\"import-Normal\">A Trace of a Simple Recursive Call<\/h2>\r\n<p class=\"import-Normal\">Suppose we are running a program that makes a call to <strong>recursiveMultiplyBy2(3)<\/strong>. Consider the simple program below.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image10-2.png\" alt=\"image\" width=\"617.142887139108px\" height=\"144px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The computer executes programs in a step-by-step manner, executing one instruction after another. In this example, suppose that the computer begins execution on line 8 at the start of the <strong>main<\/strong> procedure. As <strong>main<\/strong> needs space to store the resulting value, we can imagine that a place has been reserved for <strong>main<\/strong>\u2019s result variable and that it is stored on the stack. The following figure shows the stack at the time just before the function is called on line 8.<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image11-1.png\" alt=\"A single frame of a call stack showing a call to main.\" width=\"769\" height=\"64\" \/><\/p>\r\n<p class=\"import-Normal\">Figure 2.2<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">When the program reaches our call to <strong>recursiveMultiplyBy2(3)<\/strong>, the n variable for this call is bound with the 3 value, and these data are pushed onto the stack. The figure below gives the state of the stack just before the first line of our procedure begins execution.<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image12-1.png\" alt=\"A two-frame call stack showing a call to main and then recursiveMultiplyBy2\" width=\"754\" height=\"111\" \/><\/p>\r\n<p class=\"import-Normal\">Figure 2.3<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Here the value of 3 is bound to <strong>n<\/strong> and the execution continues line by line. As this <strong>n<\/strong> is not 0, the execution would continue to line 5, where another recursive call is made to <strong>recursiveMultiplyBy2(2)<\/strong>. This would push another stack frame onto the stack with 2 bound to <strong>n<\/strong>. This is shown in the following figure.<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image13-1.png\" alt=\"A 3-frame call stack showing a call to main and then two calls to recursiveMultiplyBy2\" width=\"779\" height=\"150\" \/><\/p>\r\n<p class=\"import-Normal\">Figure 2.4<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">You can imagine this process continuing until we reach a call that would be handled by the base case of our recursive algorithm. The base case of the algorithm acts as a signal that ends the recursion. This state is shown in the following figure:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image14-1.png\" alt=\"A multi-frame call stack showing a call to main and then multiple calls to recursiveMultiplyBy2\" width=\"782\" height=\"211\" \/><\/p>\r\n<p class=\"import-Normal\">Figure 2.5<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Next, the process of completing the calculation begins. The resulting value is returned, and the last stack frame is popped from the top of the stack.<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image15.png\" alt=\"Call stack where base case of recursive function is reached\" width=\"781\" height=\"249\" \/><\/p>\r\n<p class=\"import-Normal\">Figure 2.6<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Once the call for <strong>n = 0<\/strong> gets the returned value of 0, it may then complete its execution of line 5. This triggers the next pop from the stack, and the value of 2 + 0 = 2 is returned to the prior call with n = 2. Let\u2019s look at the stack again.<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image16-1.png\" alt=\"Call stack where recursive case is popped\" width=\"761\" height=\"204\" \/><\/p>\r\n<p class=\"import-Normal\">Figure 2.7<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">As we can see, the chain of calls is unwinding as the results are calculated in turn. This process continues. As the results are calculated and stack frames are popped, it should be clear that less memory is being used by the program. It should be noted that this implies a memory cost for deep chains of recursion. Finally, the last recursive call completes its line 5, and the value is returned to the main function as shown below.<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image17.png\" alt=\"Call stack where initial recursive case is popped\" width=\"795\" height=\"129\" \/><\/p>\r\n<p class=\"import-Normal\">Figure 2.8<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Now the main function has the result of our recursive algorithms. The value 6 is bound to the \u201cresult\u201d variable, and when the program executes the print command, \u201c6\u201d would appear on the screen. This concludes our trace of the dynamic execution of our program.<\/p>\r\n\r\n<h2 class=\"import-Normal\">Why Do We Need to Understand the Runtime Stack?<\/h2>\r\n<p class=\"import-Normal\">You may now be thinking, \u201cThis seems like a lot of detail. Why do we need to know all this stuff?\u201d There are two main reasons why we want you to better understand the runtime stack. First, it should be noted that function calls are not free. There is overhead involved in making a call to a procedure. This involves copying data to the stack, which takes time. The second concern is that making function calls, especially recursive calls, consumes memory. Understanding how algorithms consume the precious resources of time and space is fundamental to understanding computer science. We need to understand how the runtime stack works to be able to effectively reason about memory usage of our recursive algorithms.<\/p>\r\n\r\n<h1>More Examples of Recursive Algorithms<\/h1>\r\n<p class=\"import-Normal\">We have already encountered some examples of recursive algorithms in this chapter. Now we will discuss a few more to understand their power.<\/p>\r\n\r\n<h2 class=\"import-Normal\">Recursive Reverse<\/h2>\r\n<p class=\"import-Normal\">Suppose you are given the text string \u201cHELLO,\u201d and we wish to print its letters in reverse order. We can construct a recursive algorithm that prints a specific letter in the string after calling the algorithm again on the next position. Before we dive into this algorithm, let\u2019s explain a few conventions that we will use.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">First, we will treat strings as lists or arrays of characters. Characters are any symbols such as letters, numbers, or other type symbols like \u201c*,\u201d \u201c+,\u201d or \u201c&amp;.\u201d Saying they are lists or arrays means that we can access distinct positions of a string using an index. For example, let <strong>message<\/strong> be a string variable, and let its value be \u201cHELLO.\u201d If we access the elements of this array using zero-based indexing, then <strong>message[0]<\/strong> is the first letter of the string, or \u201cH.\u201d We will be using <strong>zero-based indexing<\/strong> (or 0-based indexing) in this textbook. Switching between 0-based and 1-based indexing should be easy, although it can be tricky and requires some thought when converting complex algorithms. Next, saying that a string is an array is incorrect in most programming languages. An array is specifically a fixed-size, contiguous block of memory designed to store multiple values of the same type. Most programming languages provide a string type that is more robust. Strings are usually represented as data structures that provide more functionality than just a block of memory. We will treat strings as a data structure that is like an array with a little more functionality. For example, we will assume that the functionality exists to determine the size of a string from its variable in constant time or O(1). Specifically, we will use the following function.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image18-1.png\" alt=\"image\" width=\"621.176482939633px\" height=\"44px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Back to the algorithm, we will define the base and recursive cases. The base case that terminates the algorithm will be reached by the algorithm when the position to print is greater than or equal to the length of the string. The recursive case will call the algorithm for the next position and then print the letter at the current position <em>after<\/em> the recursive call.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image19.png\" alt=\"image\" width=\"619.2px\" height=\"129px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Calling <strong>recReverse(\"HELLO\", 0)<\/strong> should give the following text printed to the screen:<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 18pt; text-indent: 18pt;\">O<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 18pt; text-indent: 18pt;\">L<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 18pt; text-indent: 18pt;\">L<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 18pt; text-indent: 18pt;\">E<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 18pt; text-indent: 18pt;\">H<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This demonstrates that the recursive algorithm can print the characters of a string in reverse order without using excessive index manipulation. Notice the order of the print statement and the recursive call. If the order of lines 7 and 8 were switched, the characters would print in their normal order. This algorithm resembles another recursive algorithm for visiting the nodes of a tree data structure that you will see in a later chapter.<\/p>\r\n\r\n<h2 class=\"import-Normal\">Wrappers and Helper Functions for Recursion<\/h2>\r\n<p class=\"import-Normal\">You may have noticed that <strong>recReverse(\"HELLO\", 0)<\/strong> seems like an odd interface for a function that reverses a string. There is an extra piece of state, the value 0, that is needed anytime we want to reverse something. Starting the reverse process in the middle of the string at index 3, for example, seems like an uncommon use case. In general, we would expect that reversing the string will almost always be done for the entire string. To address this problem, we will make a helper function. Let\u2019s create this helper function so we can call the reverse function without giving the 0 value.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image20-1.png\" alt=\"image\" width=\"621.176482939633px\" height=\"44px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Now we may call <strong>reverse(\"HELLO\")<\/strong>, which in turn, makes a call that is equivalent to <strong>revReverse(\"HELLO\", 0)<\/strong>. This design method is sometimes called <strong>wrapping<\/strong>. The recursive algorithm is wrapped in a function that simplifies the interface to the recursive algorithm. This is a very common pattern for dealing with recursive algorithms that need to carry some state of the calculation as input parameters. Some programmers may call <strong>reverse<\/strong> the wrapper and <strong>recReverse<\/strong> the helper. If your language supports access specifiers like \u201cpublic\u201d and \u201cprivate,\u201d you should make the wrapper a \u201cpublic\u201d function and restrict the helper function by making it \u201cprivate.\u201d This practice prevents programmers from accidentally mishandling the index by restricting the use of the helper function.<\/p>\r\n\r\n<h2 class=\"import-Normal\">Greatest Common Divisor<\/h2>\r\n<p class=\"import-Normal\">An algorithm for the greatest common divisor (GCD) of two integers can be formulated recursively. Suppose we have the fraction 16\/28. To simplify this fraction to 4\/7, we need to find the GCD of 16 and 28. The method known as Euclid\u2019s algorithm solves this problem by dividing two numbers, taking their remainder after division, and repeating the division step with one of the numbers and the remainder. Given two integers a and b, the algorithm proceeds according to this general process:<\/p>\r\n\r\n<ol>\r\n \t<li class=\"import-Normal\" style=\"text-indent: 0pt;\">Take two integers a and b, and let a be larger than b.<\/li>\r\n \t<li class=\"import-Normal\" style=\"text-indent: 0pt;\">Find the remainder of a \/ b, and let that number be r.<\/li>\r\n \t<li class=\"import-Normal\" style=\"text-indent: 0pt;\">If r is 0, b is the GCD; otherwise, repeat the process with b and r in place of a and b in step 1.<\/li>\r\n<\/ol>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The equations below illustrate this process. Here, let a equal 28, and let b equal 16:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">a \/ b<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">28 \/ 16=1 with remainder 12<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">16 \/ 12=1 with remainder 4<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">12 \/ 4=3 with remainder 0<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">Since the remainder is 0, the GCD is 4.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">For the fraction 16\/28, dividing the denominator and the numerator by 4 gives the simplified fraction 4\/7. This is illustrated below:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">(16 \/ 4) \/ (28 \/ 4) = 4 \/ 7.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Before we start writing the algorithm, let us think about the base case and the recursive case. What signals the end of recursion? If the remainder of a divided by b is zero, this means that b is the greatest common divisor. This should be our base case. With any other inputs, the algorithm should make a recursive call with updated inputs. Let us examine one way to implement this algorithm. We will use the keyword <strong>mod<\/strong> to mean the remainder of two integers. For example, we will take the expression <strong>7 mod 3<\/strong> to be evaluated to the value 1. The keyword <strong>mod<\/strong> is a shortened version of the word \u201cmodulo,\u201d which is the operation that calculates integer remainders after division.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image21.png\" alt=\"image\" width=\"621.538477690289px\" height=\"101px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This process will continue to reduce a and b in sequence until the remainder is 0, ultimately finding the greatest common divisor. This provides a good example of a recursive numerical algorithm that has a practical use, which is for simplifying fractions.<\/p>\r\n\r\n<h2 class=\"import-Normal\">Recursive Find Minimum<\/h2>\r\n<p class=\"import-Normal\">Finding the minimum value in a collection of numbers can be formulated as a recursive algorithm. Let us use an array of integers for this algorithm. Our algorithm will use the helper and wrapper pattern, and it will use an extra parameter to keep track of the current minimum value. Let us begin by specifying the core algorithm as a helper function. Here, as in <strong>recReverse<\/strong>, we assume a <strong>length<\/strong> function can provide the length of the array:<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image22-1.png\" alt=\"image\" width=\"624px\" height=\"200.2px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">For this algorithm, our base case occurs when the recursive process reaches the last position of the array. This signals the end of recursion, and the <strong>currentMin<\/strong> value is returned. In the recursive case, we compare the value of the current minimum with the value at the current position. Next, a recursive call is made that uses the appropriate current minimum and increases the position.<\/p>\r\n\r\n<h1 class=\"import-Normal\">Recursive Algorithms and Complexity Analysis<\/h1>\r\n<p class=\"import-Normal\">Now that we have a better understanding of recursive algorithms, how can their complexity be evaluated? Computational complexity is usually evaluated in terms of time complexity and space complexity. How does the algorithm behave when the size of the input grows arbitrarily large with respect to runtime and memory space usage? Answering these questions may be a little different for recursive algorithms than for some other algorithms you may have seen.<\/p>\r\n\r\n<h2 class=\"import-Normal\">A Warm-Up, Nonrecursive Example: Powers of 2<\/h2>\r\n<p class=\"import-Normal\">Let us begin with the nonrecursive power-of-2 algorithm from the beginning of the chapter reprinted here:<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image7-1.png\" alt=\"image\" width=\"623.283569553806px\" height=\"87px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">For this algorithm, we observe a loop that starts at 1 and continues to n. This means that we have a number of steps roughly equal to n. This is a good clue that the time complexity is linear or O(n). For an n equal to 6, we could expand this procedure to the following sequence of 5 multiplications: 2 * 2 * 2 * 2 * 2 * 2. If we added 1 to n, we would have 6 multiplications for an n of 7. Actually, according to the algorithm as written, the correct sequence for an n equal to 6 would be 1 * 2 * 2 * 2 * 2 * 2 * 2. When n is 6, this sequence has exactly n multiplications counting the first multiplication by 1. This could be optimized away, but it is a good demonstration that with or without the optimization the time complexity would be O(n). As a reminder, O(n \u2212 1) is equivalent to O(n). The time complexity O(n) is also known as <strong>linear<\/strong> time complexity.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">For this algorithm, what is the space complexity? First, let us ask how many variables are used. Well, space is needed for the input parameter <strong>n<\/strong> and the <strong>product<\/strong> variable. Are any other variables needed? In a technical sense, perhaps some space would be needed to store the literal numerical values of 1 and 2, but this may depend on the specific computer architecture in use. We ignore these issues for now. That leaves the variables <strong>n<\/strong> and <strong>product<\/strong>. If the input parameter n was assigned the value of 10, how many variables would be needed? Just two variables would be needed. If n equaled 100, how many variables would be needed? Still, only two variables would be needed. This leads us to the conclusion that only a constant number of variables are needed regardless of the size of n. Therefore, the space complexity of this algorithm is O(1), also known as <strong>constant<\/strong> space complexity.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">In summary, this iterative procedure takes O(n) time and uses O(1) space to arrive at the calculated result. <strong>Note:<\/strong> This analysis is a bit of a simplification. In reality, the size of the input is proportional to log(n) of the value, as the number n itself is represented in approximately log<sub>2<\/sub>(n) bits. This detail is often ignored, but it is worth mentioning. The point is to build your intuition for Big-O analysis by thinking about how processes need to grow with larger inputs.<\/p>\r\n\r\n<h2 class=\"import-Normal\">Recursive Powers of 2<\/h2>\r\n<p class=\"import-Normal\">Now let us consider the power-of-2 recursive algorithm from earlier and analyze its complexity.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image23.png\" alt=\"image\" width=\"629px\" height=\"87.7979002624672px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">To analyze the complexity of this algorithm, let us examine some example input values. For an n equal to 1, the algorithm begins with <strong>recursivePowerOf2(1)<\/strong>. This call evaluates <strong>2 * recursivePowerOf2(1)<\/strong>. This expression then becomes 2 * 1, which is 2. For an n equal to 3, we have the following sequence:<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 36pt; margin-right: 36pt;\">recursivePowerOf2(3) -&gt; 2 * recursivePowerOf2(2)<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 * 2 * recursivePowerOf2(1)<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 * 2 * 2 * recursivePowerOf2(0)<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 * 2 * 2 * 1<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">So for an <strong>n<\/strong> equal to 3, we have three multiplications. From this expansion of the calls, we can see that this process ultimately resembles the iterative process in terms of the number of steps. We could imagine that for an n equal to 6, <strong>recursivePowerOf2(6)<\/strong> would expand into 2 * 2 * 2 * 2 * 2 * 2 * 1 equivalent to the iterative process. From this, we can reason that the time complexity of this recursive algorithm is O(n). This general pattern is sometimes called a <strong>linear recursive process<\/strong>.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The time complexity of recursive algorithms can also be calculated using a recurrence relation. Suppose that we let T(n) represent the actual worst-case runtime of a recursive algorithm with respect to the input n. We can then write the time complexity for this algorithm as follows:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">T(0) = 1<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n) = 1 + T(n \u2212 1).<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This makes sense, as the time complexity is just the cost of one multiplication plus the cost of running the algorithm again with an input of n \u2212 1 (whatever that may be). When n is 0, we must return the value 1. This return action counts as a step in the algorithm.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Now we can use some substitution techniques to solve this recurrence relation:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=1 + T(n \u2212 1)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=1 + 1 + T(n \u2212 2)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=2 + T(n \u2212 2)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=2 + 1 + T(n \u2212 3)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=3 + T(n \u2212 3).<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\">Here we start to notice a pattern. If we continue this out to T(n \u2212 n) = T(0), we can solve the relationship:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=n + T(n \u2212 n)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=n + T(0)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=n + 1.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\">We see that T(n) = n + 1, which represents the worst-case time complexity of the algorithm. Therefore, the algorithm\u2019s time complexity is O(n + 1) = O(n).<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Next, let us analyze the space complexity. You may try to approach this problem by checking the number of variables used in the recursive procedure that implements this algorithm. Unfortunately, recursion hides some of the memory demands due to the way procedures are implemented with the runtime stack. Though it appears that only one variable is used, every call to the recursive procedure keeps its own separate value for n. This leads to a memory demand that is proportional to the number of calls made to the recursive procedure. This behavior is illustrated in the following figure, which presents a representation of the runtime stack at a point in the execution of the algorithm. Assume that <strong>recursivePowerOf2(3)<\/strong> has been called inside main or another procedure to produce a result, and we are examining the stack when the last call to <strong>recursivePowerOf2(0)<\/strong> is made during this process.<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image24-1.png\" alt=\"Diagram of a call stack intended to show convey space needs during recursive calls\" width=\"797\" height=\"258\" \/><\/p>\r\n<p class=\"import-Normal\">Figure 2.9<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The number of variables needed to calculate <strong>recursivePowerOf2(3)<\/strong> is proportional to the size of the input. The figure showing the call stack has a frame for each call starting with 3 and going down to 0. If our input increased, our memory demand would also increase. This observation leads to the conclusion that this algorithm requires O(n) space in the worst case.<\/p>\r\n\r\n<h2 class=\"import-Normal\">Tail-Call Optimization<\/h2>\r\n<p class=\"import-Normal\">In considering the two previous algorithms, we can compare them in terms of their time and space scaling behavior. The imperative <strong>powerOf2<\/strong> implementation uses a loop. This algorithm has a time complexity of O(n) and a space complexity of O(1). The <strong>recursivePowerOf2<\/strong> algorithm has a time complexity of O(n), but its space complexity is much worse at O(n). Fortunately, an optimization trick exists that allows recursive algorithms to reduce their space usage. This trick is known as tail-call optimization. If your language or compiler supports tail-call optimization, recursive algorithms can be structured to use the same amount of space as their corresponding iterative implementations. Actually, both algorithms would be considered iterative, as they iteratively update a fixed set of state variables. Let us examine a tail-call optimization example in greater detail.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">To fix our <strong>recursivePowerOf2<\/strong> implementation\u2019s space complexity issues, we will first slightly modify our algorithm. We will add a state variable that will hold the running product. This serves the same purpose as the product variable in our iterative loop implementation.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image25.png\" alt=\"image\" width=\"619px\" height=\"86.4020997375328px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">For this algorithm to work correctly, any external call should be made with <strong>product<\/strong> set to 1. This ensures that an exponent of n equal to 0 returns 1. This means it would be a good idea to wrap this algorithm in a wrapper function to avoid unnecessary errors when a programmer mistakenly calls the algorithm without <strong>product<\/strong> set to 1. This simple wrapper function is presented below:<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image26-1.png\" alt=\"image\" width=\"612px\" height=\"43.3500262467192px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">To understand how tail-call optimization works, let us think about what would happen on the stack when we made a call like <strong>recursivePowerOf2(1, 3)<\/strong> using our new algorithm (we will ignore the wrapper for this discussion). The stack without tail-call optimization would look like the following figure:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image27.png\" alt=\"Call stack diagram of a recursive funciton which cannot leverage tail call optimization.\" width=\"757\" height=\"263\" \/><\/p>\r\n<p class=\"import-Normal\">Figure 2.10<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The key observation of tail-call optimization is that when the recursive call is at the tail end of the procedure (in this case, line 5), no information is needed from the current stack frame. This means that the current frame can simply be reused without consuming more memory. The following figure gives an illustration of <strong>recursivePowerOf2(1, 3)<\/strong> after the first recursive tail-call in the execution process.<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image28-1.png\" alt=\"Call stack diagram of a recursive funciton which can leverage tail call optimization\" width=\"757\" height=\"167\" \/><\/p>\r\n<p class=\"import-Normal\">Figure 2.11<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Using tail-call optimization, our new <strong>recursivePowerOf2<\/strong> algorithm has the same time complexity O(n) and space complexity O(1) as the loop-based iterative implementation. Keep in mind that tail-call optimization is a feature of either your interpreter or the compiler. You may wish to check if it is supported by your language (https:\/\/en.wikipedia.org\/wiki\/Tail_call#By_language).<\/p>\r\n\r\n<h2 class=\"import-Normal\">Powers of 2 in O(log n) Time<\/h2>\r\n<p class=\"import-Normal\">A clever algorithm is presented in Structure and Interpretation of Computer Programs (SICP, Abelson and Sussman, 1996) that calculates powers of any base in O(log n) time. Let us examine this algorithm to help us understand some recursive algorithms that are faster\u2014or rather, scale better\u2014than O(n) time.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">We will examine the same problem as above, calculating the nth power of 2. The key idea of this algorithm takes advantage of the fact that 2<sup>n<\/sup> = (2<sup>n\/2<\/sup>)<sup>2<\/sup> when n is even and 2 * 2<sup>n\u22121<\/sup> when n is odd. To implement this algorithm, we must first define two helper functions. One function will square an input number, and the other function will check if a number is even. We will define them here using <strong>mod<\/strong> to indicate the remainder after division.<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image29-1.png\" alt=\"image\" width=\"619.2px\" height=\"129px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">After defining these two functions, we will consider the bases and recursive cases for which we need to account. If n is 0, the algorithm should return 1 according to the mathematical definition of any base value raised to an exponent of 0. This will be one of our cases. Next, if the n is even, we will square the result of a recursive call to the algorithm passing the value of n\/2. This code is equivalent to our calculation of (2<sup>n\/2<\/sup>)<sup>2<\/sup>. Lastly, for the odd case, we will calculate 2 times the result of a recursive call that passes the value of n \u2212 1. This code handles the odd case equivalent to 2 * 2<sup>n\u22121<\/sup> and sets up the use of our efficient even exponent case. The algorithm is presented below:<\/p>\r\n<p class=\"import-Normal\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image30-1.png\" alt=\"image\" width=\"624px\" height=\"116.333333333333px\" \/><\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Let us think about the process this algorithm uses to calculate 2<sup>9<\/sup>. This process starts with a call to <strong>fastPowerOf2(9)<\/strong>. Since 9 is odd, we would multiply <strong>2 * fastPowerOf2(8)<\/strong>. This expression then expands to <strong>2 * square(fastPowerOf2(4))<\/strong>. Let us look at this in more detail.<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 36pt; margin-right: 36pt;\">fastPowerOf2(9)-&gt;2 * fastPowerOf2(8)<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(fastPowerOf2(4))<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(square(fastPowerOf2(2)))<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(square(square(fastPowerOf2(1))))<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(square(square(2 * fastPowerOf2(0))))<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(square(square(2 * 1)))<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(square(4))<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(16)<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * 256<\/p>\r\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;512<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">It may not be clear that this algorithm is faster than the previous <strong>recursivePowerOf2<\/strong>, which was bounded by O(n). Considering the linear calculation of 2<sup>9<\/sup> would look like this: 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 with 9 multiplications. For this algorithm, we could start thinking about the calculation that is equivalent to <strong>2 * square(square(square(2 * 1)))<\/strong>. Our first multiplication is 2 * 1. Next, the <strong>square<\/strong> procedure multiplies 2 * 2 to get 4. Then 4 is squared, and then 16 is squared for 2 more multiplications. Finally, we get 2 * 256, giving the solution of 512 after only 5 multiply operations. At least for an n of 9, <strong>fastPowerOf2<\/strong> uses fewer multiply operations. From this, we could imagine that for larger values of n, the <strong>fastPowerOf2<\/strong> algorithm would yield even more savings with fewer total operations compared to the linear algorithm.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Let us now examine the time complexity of <strong>fastPowerOf2<\/strong> using a recurrence relation. The key insight is that roughly every time the recursive algorithm is called, n is cut in half. We could model this as follows: Let us assume that there is a small constant number of operations associated with each call to the recursive procedure. We will represent this as c. Again, we will use the function T(n) to represent the worse-case number of operations for the algorithm. So for this algorithm, we have T(n) = c + T(n\/2). Let us write this and the base case as a recurrence relation:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">T(0)=c<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=c + T(n\/2).<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">To solve this recurrence problem, we begin by making substitutions and looking for a pattern:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=c + T(n\/2)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">\u00a0\u00a0\u00a0=c + c + T(n\/4)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">\u00a0\u00a0\u00a0=c + c + c + T(n\/8).<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">We are beginning to see a pattern, but it may not be perfectly clear. The key is in determining how many of those constant terms there will be once the expression of T(n\/x) becomes 1 or 0. Let us rewrite these terms in a different way:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=c + T(n\/2<sup>1<\/sup>)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">\u00a0\u00a0\u00a0=2c + T(n\/2<sup>2<\/sup>)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">\u00a0\u00a0\u00a0=3c + T(n\/2<sup>3<\/sup>).<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\">Now we seek a pattern that is a little clearer:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">T(n)=k * c + T(n\/2<sup>k<\/sup>).<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\">So when will n\/2<sup>k<\/sup> be 1?<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">We can solve for k in the following equation:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">n\/2<sup>k<\/sup>=1<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">2<sup>k<\/sup> * (n\/2<sup>k<\/sup>)=2<sup>k<\/sup> * 1<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">n=2<sup>k<\/sup>.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\">Now taking the log<sub>2<\/sub> of each side gives the following:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">log<sub>2<\/sub> n=k.<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\">Now we can rewrite the original formula:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p style=\"text-align: center;\">T(n)=log<sub>2<\/sub> n * c + T(1).<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">According to our algorithm, with <strong>n<\/strong> equal to 1, we use the odd case giving 2 * <strong>fastPowerOf2(0)<\/strong> = 1. So we could reason that T(1) = 2c. Finally, we can remove the recursive terms and with a little rewriting arrive at the time complexity:<\/p>\r\n\r\n<div class=\"textbox standard\">\r\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=log<sub>2<\/sub> n * c + T(1)<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=log<sub>2<\/sub> n * c + 2c<\/p>\r\n<p class=\"import-Normal\" style=\"text-align: center;\">=c * (log<sub>2<\/sub> n + 2).<\/p>\r\n\r\n<\/div>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Therefore, our asymptotic time complexity is O(log n)<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Here we have some constants and lower-order terms that lead us to a time complexity of O(log n). This means that the scaling behavior of <strong>fastPowerOf2<\/strong> is much, much better than our linear version. For reference, suppose n was set to 1,000. A linear algorithm would take around 1,000 operations, whereas an O(log n) algorithm would only take around 20 operations.<\/p>\r\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">As for space complexity, this algorithm does rely on a nested call that needs information from previous executions. This requirement is due to the square function that needs the result of the recursive call to return. This implementation is not tail-recursive. In determining the space complexity, we need to think about how many nested calls need to be made before we reach a base case to signal the end of recursion. For a process like this, all these calls will consume memory by storing data on the runtime stack. As n is divided each time, we will reach a base case after O(log n) recursive calls. This means that in the worst case, the algorithm will have O(log n) stack frames taking up memory. Put simply, its space complexity is O(log n).<\/p>\r\n&nbsp;\r\n<div class=\"textbox textbox--exercises\"><header class=\"textbox__header\">\r\n<p class=\"textbox__title\">Exercises<\/p>\r\n\r\n<\/header>\r\n<div class=\"textbox__content\">\r\n<ol class=\"legal\">\r\n \t<li>Write a recursive function like that of <strong>powerOf2<\/strong> called \u201cpow\u201d that takes a <strong>base<\/strong> and <strong>exponent<\/strong> variables and computes the value of <strong>base<\/strong> raised to the <strong>exponent<\/strong> power for any integer base &gt;= 1 and any integer exponent &gt;= 0.<\/li>\r\n \t<li>The sequence {0, 1, 3, 6, 10, 15, 21, 28, \u2026 } gives the sequence of triangular numbers.\r\n<ol>\r\n \t<li>Give a recursive definition of the triangular numbers (starting with n = 0).<\/li>\r\n \t<li>Give a recursive algorithm for calculating the nth triangular number.<\/li>\r\n<\/ol>\r\n<\/li>\r\n \t<li>Modify the <strong>recMin<\/strong> algorithm to create a function called <strong>recMinIndex<\/strong>. Your algorithm should return the index of the minimum value in the array rather than the minimum value itself. <strong>Hint:<\/strong> You should add another parameter to the helper function that keeps track of the minimum value\u2019s index.<\/li>\r\n \t<li>Write an algorithm called <strong>simplify<\/strong> that prints the simplified output of a fraction. Have the procedure accept two integers representing the numerator and denominator of a fraction. Have the algorithm print a simplified representation of the fraction. For example, <strong>simplify(8, 16)<\/strong> should print \u201c1 \/ 2.\u201d Use the GCD algorithm as a subroutine in your procedure.<\/li>\r\n \t<li>Implement the three <strong>powerOf2<\/strong> algorithms (iterative, recursive, and <strong>fastPowerOf2<\/strong>) in your language of choice. Calculate the runtime of the different algorithms, and determine which algorithms perform best for which values of n. Using your data, create a \u201csuper\u201d algorithm that checks the size of n and calls the most efficient algorithm depending on the value of n.<\/li>\r\n<\/ol>\r\n<\/div>\r\n<\/div>\r\n&nbsp;\r\n<div class=\"textbox textbox--key-takeaways\"><header class=\"textbox__header\">\r\n<p class=\"textbox__title\">References<\/p>\r\n\r\n<\/header>\r\n<div class=\"textbox__content\">\r\n<p class=\"import-Normal hanging-indent\">Abelson, Harold, and Gerald Jay Sussman. <em>Structure and Interpretation of Computer Programs<\/em>. The MIT Press, 1996.<\/p>\r\n\r\n<\/div>\r\n<\/div>\r\n&nbsp;","rendered":"<div class=\"textbox textbox--learning-objectives\">\n<header class=\"textbox__header\">\n<p class=\"textbox__title\">Learning Objectives<\/p>\n<\/header>\n<div class=\"textbox__content\">\n<p class=\"import-Normal\">After reading this chapter you will\u2026<\/p>\n<ul>\n<li class=\"import-Normal\">understand the features of recursion and recursive processes.<\/li>\n<li class=\"import-Normal\">be able to identify the components of a recursive algorithm.<\/li>\n<li class=\"import-Normal\">be able to implement some well-known recursive algorithms.<\/li>\n<li class=\"import-Normal\">be able to estimate the complexity of recursive processes.<\/li>\n<li class=\"import-Normal\">understand the benefits of recursion as a problem-solving strategy.<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<h1 class=\"import-Normal\">Introduction<\/h1>\n<p class=\"import-Normal\">Recursion is a powerful tool for computation that often saves the programmer considerable work. As you will see, the benefit of recursion lies in its ability to simplify the code of algorithms, but first we want to better understand recursion. Let\u2019s look at a simple nonrecursive function to calculate the product of 2 times a nonnegative integer, n, by repeated addition:<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image5.png\" alt=\"image\" width=\"618px\" height=\"86.262467191601px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This function takes a number, n, as an input parameter and then defines a procedure to repeatedly add 2 to a sum. This approach to calculation uses a for-loop explicitly. Such an approach is sometimes referred to as an iterative process. This means that the calculation repeatedly modifies a fixed number of variables that change the current \u201cstate\u201d of the calculation. Each pass of the loop updates these state variables, and they evolve toward the correct value. Imagine how this process will evolve as a computer executes the function call <strong>multiplyBy2(3)<\/strong>. A \u201ccall\u201d asks the computer to evaluate the function by executing its code.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">When the process starts, <strong>sum<\/strong> is 0. Then the process iteratively adds 2 to the <strong>sum<\/strong>. The process generated is equivalent to the mathematical expression (2 + 2 + 2). The following table shows the value of each variable (<strong>i<\/strong>, <strong>sum<\/strong>, and <strong>n<\/strong>) at each time step:<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter wp-image-861\"><img class=\"aligncenter wp-image-861\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/2.1.png\" alt=\"A table showing how multiplication can be performed using successive addition of a non-negative value.\" width=\"529\" height=\"191\" srcset=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/2.1.png 587w, https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/2.1-300x108.png 300w, https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/2.1-65x23.png 65w, https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/2.1-225x81.png 225w, https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/2.1-350x126.png 350w\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.1<\/p>\n<\/div>\n<h2 class=\"import-Normal\">Recursive Multiplication<\/h2>\n<p class=\"import-Normal\">Like iterative procedures, recursive procedures are a means to repeat certain operations in code. We will now write a recursive function to calculate the multiplication by 2 as a sequence of addition operations.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image6-1.png\" alt=\"image\" width=\"616px\" height=\"85.9833070866142px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The recursive formulation follows the mathematical intuition that 2 * n = 2 + 2 * (n \u2212 1) = 2 + 2 + 2 * (n \u2212 2) \u2026 and so on until you reach 2 + 2 + 2 + \u2026 2 * 1. We can visualize this process by considering how a computer might evaluate the function call <strong>recursiveMultiplyBy2(3)<\/strong>. The evaluation process is similar conceptually to a rewriting process.<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 36pt; margin-right: 36pt;\">recursiveMultiplyBy2(3) -&gt; 2 + recursiveMultiplyBy2(2)<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 + 2 + recursiveMultiplyBy2(1)<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 + 2 + 2 + recursiveMultiplyBy2(0)<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 + 2 + 2 + 0<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 + 2 + 2<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 6<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This example demonstrates a few features of a recursive procedure. Perhaps the most recognizable feature is that it makes a call to itself. We can see that <strong>recursiveMultiplyBy2<\/strong> makes a call to <strong>recursiveMultiplyBy2<\/strong> in the else part of the procedure. As an informal definition, a recursive procedure is one that calls to itself (either directly or indirectly). Another feature of this recursive procedure is that the action of the process is broken into two parts. The first part directs the procedure to return 0 when the input, n, is equal to 0. The second part addresses the other case where n is not 0. We now have some understanding of the features of all recursive procedures.<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 0pt; text-indent: 0pt;\">Features of Recursive Procedures<\/p>\n<ul>\n<li class=\"import-Normal\" style=\"text-indent: 0pt;\">A recursive procedure makes reference to itself as a procedure. This self-call is known as the recursive call.<\/li>\n<li class=\"import-Normal\" style=\"text-indent: 0pt;\">Recursive procedures divide work into two cases based on the value of their inputs.\n<ul>\n<li class=\"import-Normal\" style=\"text-indent: 0pt;\">One case is known as the base case.<\/li>\n<li class=\"import-Normal\" style=\"text-indent: 0pt;\">The other case is known as the recursive case or sometimes the general case.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2 class=\"import-Normal\">Recursive Exponentiation<\/h2>\n<p class=\"import-Normal\">Let us now consider another example. Just as multiplication can be modeled as repeated addition, exponentiation can be modeled as repeated multiplication. Suppose we wanted to modify our iterative procedure for multiplying by 2 to create an iterative procedure for calculating powers of 2 for any nonnegative integer n. How might we modify our procedure? We might simply change the operation from + (add) to * (multiply).<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image7.png\" alt=\"image\" width=\"623.283569553806px\" height=\"87px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This procedure calculates a power of 2 for any nonnegative integer n. We changed not only the operation but also the starting value from 0 to 1.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">We can also write this procedure recursively, but first let us think about how to formulate this mathematically by looking at an example. Suppose we want to calculate 2<sup>3<\/sup>:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">2<sup>3<\/sup>=2 * 2<sup>2<\/sup><\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=2 * 2 * 2<sup>1<\/sup><\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=2 * 2 * 2 * 2<sup>0<\/sup><\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=2 * 2 * 2 * 1=8.<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The explicit 2<sup>0<\/sup> is shown to help us think about the recursive and base cases. From this example, we can formulate two general rules about exponentiation using 2 as the base:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">2<sup>0<\/sup>=1<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">2<sup>n<\/sup>=2 * 2<sup>(n\u22121)<\/sup>.<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Now let\u2019s write the recursive procedure for this function. Try to write this on your own before looking at the solution.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image8-1.png\" alt=\"image\" width=\"620px\" height=\"86.5416272965879px\" \/><\/div>\n<h1 class=\"import-Normal\">The Structure of Recursive Algorithms<\/h1>\n<p class=\"import-Normal\">As mentioned above, recursive procedures have a certain structure that relies on self-reference and splitting the input into cases based on its value. Here we will discuss the structure of recursive procedures and give some background on the motivation for recursion.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Before we begin, recall from chapter 1 that a procedure can be thought of as a specific implementation of an algorithm. While these are indeed two separate concepts, they can often be used interchangeably when considering pseudocode. This is because the use of an algorithm in practice should be made as simple as possible. Often this is accomplished by wrapping the algorithm in a simple procedure. This design simplifies the interface, allowing the programmer to easily use the algorithm in some other software context such as a program or application. In this chapter, you can treat algorithm and procedure as the same idea.<\/p>\n<h2 class=\"import-Normal\">Some Background on Recursion<\/h2>\n<p class=\"import-Normal\">The concept of recursion originated in the realm of mathematics. It was found that some interesting mathematical sequences could be defined in terms of themselves, which greatly simplified their definitions. Take for example the Fibonacci sequence:<\/p>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, \u2026 }.<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This sequence is likely familiar to you. The sequence starts at 0, 0 is followed by 1, and each subsequent value in the sequence is derived from the previous two elements in the sequence. This seemingly simple sequence is fairly difficult to define in an explicit way. Let\u2019s look a bit closer.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Based on the sequence above, we see the following equations are true:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>0<\/sub> = 0<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>1<\/sub> = 1<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>2<\/sub> = 1<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>3<\/sub> = 2<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>4<\/sub> = 3.<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Using this formulation, we may wish to find a function that would calculate the nth Fibonacci number given any positive integer, n:<\/p>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">F<sub>n<\/sub> = ?.<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Finding such a function that depends only on n is not trivial. This also leads to some difficulties in formally defining the sequence. To partially address this issue, we can use a recursive definition. This allows the sequence to be specified using a set of simple rules that are self-referential in nature. These recursive rules are referred to in mathematics as recurrence relations. Let\u2019s look at the recurrence relation for the Fibonacci sequence:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>0<\/sub>=0<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>1<\/sub>=1<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>n<\/sub>=F<sub>n\u22121<\/sub> + F<sub>n\u22122<\/sub>.<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This gives a simple and perfectly correct definition of the sequence, and we can calculate the nth Fibonacci number for any positive integer n. Suppose we wish to calculate the eighth Fibonacci number. We can apply the definition and then repeatedly apply it until we reach the F<sub>0<\/sub> and F<sub>1<\/sub> cases that are explicitly defined:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>8<\/sub>=F<sub>8\u22121<\/sub> + F<sub>8\u22122<\/sub><\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=F<sub>7<\/sub> + F<sub>6<\/sub><\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=(F<sub>7\u22121<\/sub> + F<sub>7\u22122<\/sub>) + (F<sub>6\u22121<\/sub> + F<sub>6\u22122<\/sub>)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">\u2026and so on.<\/p>\n<\/div>\n<p class=\"import-Normal\">This may be a long process if we are doing this by hand. This could be an especially long process if we fail to notice that F<sub>7\u22122<\/sub> is the same as F<sub>6\u22121<\/sub>.<\/p>\n<h2 class=\"import-Normal\">A Trade-Off with Recursion<\/h2>\n<p class=\"import-Normal\">Observing this process leads us to another critical insight about recursive processes. What may be simple to describe may not be efficient to calculate. This is one of the major drawbacks of recursion in computing. You may be able to easily specify a correct algorithm using recursion in your code, but that implementation may be wildly inefficient. Recursive algorithms can usually be rewritten to be more efficient. Unfortunately, the efficiency of the implementation comes with the cost of losing the simplicity of the recursive code. Sacrificing simplicity leads to a more difficult implementation. Difficult implementations allow for more bugs.<\/p>\n<h2 class=\"import-Normal\">An Aside on Navigating the Efficiency-Simplicity Trade-Off<\/h2>\n<p class=\"import-Normal\">In considering the trade-off between efficiency and simplicity, context is important, and there is no \u201cright\u201d answer. A good guideline is to focus on correct implementations first and optimize when there is a problem (verified by empirical tests). Donald Knuth references Tony Hoare as saying \u201cpremature optimization is the root of all evil\u201d in programming. This should not be used as an excuse to write inefficient code. It takes time to write efficient code. \u201cI was optimizing the code\u201d is a poor excuse for missed deadlines. Make sure the payoff justifies the effort.<\/p>\n<h2 class=\"import-Normal\">Recursive Structure<\/h2>\n<p class=\"import-Normal\">The recursive definition of the Fibonacci sequence can be divided into two parts. The first two equations establish the first two values of the sequence explicitly by definition for n = 0 and n = 1. The last equation defines Fibonacci values in the general case for any integer n &gt; 1. The last equation uses recursion to simplify the general case. Let\u2019s rewrite this definition and label the different parts.<\/p>\n<h1 class=\"import-Normal\">Base Cases<\/h1>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>0<\/sub> = 0<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">F<sub>1<\/sub> = 1<\/p>\n<\/div>\n<h1 class=\"import-Normal\">Recursive Case<\/h1>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">F<sub>n<\/sub> = F<sub>n\u22121<\/sub> + F<sub>n\u22122<\/sub><\/p>\n<\/div>\n<p class=\"import-Normal\">Recursive algorithms have a similar structure. A recursive procedure is designed using the base case (or base cases) and a recursive case. The base cases may be used to explicitly define the output of a calculation, or they may be used to signal the end of a recursive process and stop the repeated execution of a procedure. The recursive case makes a call to the function itself to solve a portion of the original problem. This is the general structure of a recursive algorithm. Let\u2019s use these ideas to formulate a simple algorithm to calculate the nth Fibonacci number. Before we begin, let\u2019s write the cases we need to consider.<\/p>\n<h1 class=\"import-Normal\">Base Cases<\/h1>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">n = 0 the algorithm should return 0<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">n = 1 the algorithm should return 1<\/p>\n<\/div>\n<h1 class=\"import-Normal\">Recursive Case<\/h1>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">any other n the algorithm returns the sum of Fibonacci(n \u2212 1) and Fibonacci(n \u2212 2)<\/p>\n<\/div>\n<p class=\"import-Normal\">Now we define the recursive algorithm to calculate the nth Fibonacci number.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image9-1.png\" alt=\"image\" width=\"618.731338582677px\" height=\"116.01217847769px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">In this algorithm, conditional if-statements are used to select the appropriate action based on the input value of n. If the value is 0 or 1, the input is handled by a base case, and the function directly returns the appropriate value. If another integer is input, the recursive case handles the calculation, and two more calls to the procedure are executed. You may be thinking, \u201cWait, for every function call, it calls itself two more times? That doesn\u2019t sound efficient.\u201d You would be right. This is not an efficient way to calculate the Fibonacci numbers. We will revisit this idea in more detail later in the chapter.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Before we move on, let us revisit the two examples from the introduction, multiplication and exponentiation. We can define these concepts using recurrence relations too. We will use the generic letter a for these definitions.<\/p>\n<h3 class=\"import-Normal\">Multiplication by 2<\/h3>\n<h1 class=\"import-Normal\">Base Case<\/h1>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">a<sub>0<\/sub> = 0<\/p>\n<\/div>\n<h1 class=\"import-Normal\">Recursive Case<\/h1>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">a<sub>n<\/sub> = 2 + a<sub>n\u22121<\/sub><\/p>\n<\/div>\n<h3 class=\"import-Normal\">Powers of 2<\/h3>\n<h1 class=\"import-Normal\">Base Case<\/h1>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">a<sub>0<\/sub> = 1<\/p>\n<\/div>\n<h1 class=\"import-Normal\">Recursive Case<\/h1>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">a<sub>n<\/sub> = 2 * a<sub>n\u22121<\/sub><\/p>\n<\/div>\n<p class=\"import-Normal\">Looking back at the recursive functions for these algorithms, we see they have a shared structure that uses conditionals to select the correct case based on the input, and the base cases and recursive cases handle the calculation by ending the chain of recursive calls or by adding to the chain of calls respectively. In the next section, we will examine some important details of how a computer executes these function definitions as dynamic processes to generate the correct result of a calculation.<\/p>\n<h1 class=\"import-Normal\">Recursion and the Runtime Stack<\/h1>\n<p class=\"import-Normal\">Thus far, we have relied on your intuitive understanding of how a computer executes function calls. Unless you have taken a computer organization or assembly language course, this process may seem a little mysterious. How does the computer execute the same procedure and distinguish the call to <strong>recursiveMultiplyBy2(3)<\/strong> from the call to <strong>recursiveMultiplyBy2(2)<\/strong> that arises from the previous function call? Both calls utilize the same definition, but one has the value 3 bound to <strong>n<\/strong> and the other has the value 2 bound to <strong>n<\/strong>. Furthermore, the result of <strong>recursiveMultiplyBy2(2)<\/strong> is needed by the call to <strong>recursiveMultiplyBy2(3)<\/strong> before a value may be returned. This requires that a separate value of n needs to be stored in memory for each execution of the function during the evaluation process. Most modern computing systems utilize what is known as a runtime stack to solve this problem.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">A stack is a simple data structure where data are placed on the top and removed from the top. Like a stack of books, to get to a book in the middle, one must first remove the books on top. We will address stacks in more detail in a later chapter, but we will briefly introduce the topic. Here we will examine how a runtime stack is used to store the necessary data for the execution of a recursive evaluation process.<\/p>\n<h2 class=\"import-Normal\">The Runtime Stack<\/h2>\n<p class=\"import-Normal\">We will give a rough description of the runtime stack. This should be taken as a cartoon version or caricature of the actual runtime stack. We encourage you to supplement your understanding of this topic by exploring some resources on computer organization and assembly language. The real-world details of computer systems can be as important as the abstract view presented here.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The runtime stack is a section of memory that stores data associated with the dynamic execution of many function calls. When a function is called at runtime, all the data associated with that function call, including input arguments and locally defined variables, are placed on the stack. This is known as \u201cpushing\u201d to the stack. The data that was pushed onto the stack represents the state of the function call as it is executing. You can think of this as the function\u2019s local environment during execution. We call this data stored on the stack a <strong>stack frame<\/strong>. The stack frame is a contiguous section of the stack that is associated with a specific call to a procedure. There may be many separate stack frames for the same procedure. This is the case with recursion, where the same function is called many times with distinct inputs.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Once the execution of a function completes, its data are no longer needed. At the time of completion, the function\u2019s data are removed from the top of the stack or \u201cpopped.\u201d Popping data from the runtime stack frees it, in a sense, and allows that memory to be used for other function calls that may happen later in the program execution. As the final two steps in the execution of the procedure, the function\u2019s stack frame is popped, and its return value (if the function returns a value) is passed to the caller of the function. The calling function may be a \u201cmain\u201d procedure that is driving the program, or it may be another call to the same function as in recursion. This allows the calling function to proceed with its execution. Let\u2019s trace a simple recursive algorithm to better understand this process.<\/p>\n<h2 class=\"import-Normal\">A Trace of a Simple Recursive Call<\/h2>\n<p class=\"import-Normal\">Suppose we are running a program that makes a call to <strong>recursiveMultiplyBy2(3)<\/strong>. Consider the simple program below.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image10-2.png\" alt=\"image\" width=\"617.142887139108px\" height=\"144px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The computer executes programs in a step-by-step manner, executing one instruction after another. In this example, suppose that the computer begins execution on line 8 at the start of the <strong>main<\/strong> procedure. As <strong>main<\/strong> needs space to store the resulting value, we can imagine that a place has been reserved for <strong>main<\/strong>\u2019s result variable and that it is stored on the stack. The following figure shows the stack at the time just before the function is called on line 8.<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image11-1.png\" alt=\"A single frame of a call stack showing a call to main.\" width=\"769\" height=\"64\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.2<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">When the program reaches our call to <strong>recursiveMultiplyBy2(3)<\/strong>, the n variable for this call is bound with the 3 value, and these data are pushed onto the stack. The figure below gives the state of the stack just before the first line of our procedure begins execution.<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image12-1.png\" alt=\"A two-frame call stack showing a call to main and then recursiveMultiplyBy2\" width=\"754\" height=\"111\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.3<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Here the value of 3 is bound to <strong>n<\/strong> and the execution continues line by line. As this <strong>n<\/strong> is not 0, the execution would continue to line 5, where another recursive call is made to <strong>recursiveMultiplyBy2(2)<\/strong>. This would push another stack frame onto the stack with 2 bound to <strong>n<\/strong>. This is shown in the following figure.<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image13-1.png\" alt=\"A 3-frame call stack showing a call to main and then two calls to recursiveMultiplyBy2\" width=\"779\" height=\"150\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.4<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">You can imagine this process continuing until we reach a call that would be handled by the base case of our recursive algorithm. The base case of the algorithm acts as a signal that ends the recursion. This state is shown in the following figure:<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image14-1.png\" alt=\"A multi-frame call stack showing a call to main and then multiple calls to recursiveMultiplyBy2\" width=\"782\" height=\"211\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.5<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Next, the process of completing the calculation begins. The resulting value is returned, and the last stack frame is popped from the top of the stack.<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image15.png\" alt=\"Call stack where base case of recursive function is reached\" width=\"781\" height=\"249\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.6<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Once the call for <strong>n = 0<\/strong> gets the returned value of 0, it may then complete its execution of line 5. This triggers the next pop from the stack, and the value of 2 + 0 = 2 is returned to the prior call with n = 2. Let\u2019s look at the stack again.<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image16-1.png\" alt=\"Call stack where recursive case is popped\" width=\"761\" height=\"204\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.7<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">As we can see, the chain of calls is unwinding as the results are calculated in turn. This process continues. As the results are calculated and stack frames are popped, it should be clear that less memory is being used by the program. It should be noted that this implies a memory cost for deep chains of recursion. Finally, the last recursive call completes its line 5, and the value is returned to the main function as shown below.<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image17.png\" alt=\"Call stack where initial recursive case is popped\" width=\"795\" height=\"129\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.8<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Now the main function has the result of our recursive algorithms. The value 6 is bound to the \u201cresult\u201d variable, and when the program executes the print command, \u201c6\u201d would appear on the screen. This concludes our trace of the dynamic execution of our program.<\/p>\n<h2 class=\"import-Normal\">Why Do We Need to Understand the Runtime Stack?<\/h2>\n<p class=\"import-Normal\">You may now be thinking, \u201cThis seems like a lot of detail. Why do we need to know all this stuff?\u201d There are two main reasons why we want you to better understand the runtime stack. First, it should be noted that function calls are not free. There is overhead involved in making a call to a procedure. This involves copying data to the stack, which takes time. The second concern is that making function calls, especially recursive calls, consumes memory. Understanding how algorithms consume the precious resources of time and space is fundamental to understanding computer science. We need to understand how the runtime stack works to be able to effectively reason about memory usage of our recursive algorithms.<\/p>\n<h1>More Examples of Recursive Algorithms<\/h1>\n<p class=\"import-Normal\">We have already encountered some examples of recursive algorithms in this chapter. Now we will discuss a few more to understand their power.<\/p>\n<h2 class=\"import-Normal\">Recursive Reverse<\/h2>\n<p class=\"import-Normal\">Suppose you are given the text string \u201cHELLO,\u201d and we wish to print its letters in reverse order. We can construct a recursive algorithm that prints a specific letter in the string after calling the algorithm again on the next position. Before we dive into this algorithm, let\u2019s explain a few conventions that we will use.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">First, we will treat strings as lists or arrays of characters. Characters are any symbols such as letters, numbers, or other type symbols like \u201c*,\u201d \u201c+,\u201d or \u201c&amp;.\u201d Saying they are lists or arrays means that we can access distinct positions of a string using an index. For example, let <strong>message<\/strong> be a string variable, and let its value be \u201cHELLO.\u201d If we access the elements of this array using zero-based indexing, then <strong>message[0]<\/strong> is the first letter of the string, or \u201cH.\u201d We will be using <strong>zero-based indexing<\/strong> (or 0-based indexing) in this textbook. Switching between 0-based and 1-based indexing should be easy, although it can be tricky and requires some thought when converting complex algorithms. Next, saying that a string is an array is incorrect in most programming languages. An array is specifically a fixed-size, contiguous block of memory designed to store multiple values of the same type. Most programming languages provide a string type that is more robust. Strings are usually represented as data structures that provide more functionality than just a block of memory. We will treat strings as a data structure that is like an array with a little more functionality. For example, we will assume that the functionality exists to determine the size of a string from its variable in constant time or O(1). Specifically, we will use the following function.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image18-1.png\" alt=\"image\" width=\"621.176482939633px\" height=\"44px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Back to the algorithm, we will define the base and recursive cases. The base case that terminates the algorithm will be reached by the algorithm when the position to print is greater than or equal to the length of the string. The recursive case will call the algorithm for the next position and then print the letter at the current position <em>after<\/em> the recursive call.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image19.png\" alt=\"image\" width=\"619.2px\" height=\"129px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Calling <strong>recReverse(&#8220;HELLO&#8221;, 0)<\/strong> should give the following text printed to the screen:<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 18pt; text-indent: 18pt;\">O<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 18pt; text-indent: 18pt;\">L<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 18pt; text-indent: 18pt;\">L<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 18pt; text-indent: 18pt;\">E<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 18pt; text-indent: 18pt;\">H<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This demonstrates that the recursive algorithm can print the characters of a string in reverse order without using excessive index manipulation. Notice the order of the print statement and the recursive call. If the order of lines 7 and 8 were switched, the characters would print in their normal order. This algorithm resembles another recursive algorithm for visiting the nodes of a tree data structure that you will see in a later chapter.<\/p>\n<h2 class=\"import-Normal\">Wrappers and Helper Functions for Recursion<\/h2>\n<p class=\"import-Normal\">You may have noticed that <strong>recReverse(&#8220;HELLO&#8221;, 0)<\/strong> seems like an odd interface for a function that reverses a string. There is an extra piece of state, the value 0, that is needed anytime we want to reverse something. Starting the reverse process in the middle of the string at index 3, for example, seems like an uncommon use case. In general, we would expect that reversing the string will almost always be done for the entire string. To address this problem, we will make a helper function. Let\u2019s create this helper function so we can call the reverse function without giving the 0 value.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image20-1.png\" alt=\"image\" width=\"621.176482939633px\" height=\"44px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Now we may call <strong>reverse(&#8220;HELLO&#8221;)<\/strong>, which in turn, makes a call that is equivalent to <strong>revReverse(&#8220;HELLO&#8221;, 0)<\/strong>. This design method is sometimes called <strong>wrapping<\/strong>. The recursive algorithm is wrapped in a function that simplifies the interface to the recursive algorithm. This is a very common pattern for dealing with recursive algorithms that need to carry some state of the calculation as input parameters. Some programmers may call <strong>reverse<\/strong> the wrapper and <strong>recReverse<\/strong> the helper. If your language supports access specifiers like \u201cpublic\u201d and \u201cprivate,\u201d you should make the wrapper a \u201cpublic\u201d function and restrict the helper function by making it \u201cprivate.\u201d This practice prevents programmers from accidentally mishandling the index by restricting the use of the helper function.<\/p>\n<h2 class=\"import-Normal\">Greatest Common Divisor<\/h2>\n<p class=\"import-Normal\">An algorithm for the greatest common divisor (GCD) of two integers can be formulated recursively. Suppose we have the fraction 16\/28. To simplify this fraction to 4\/7, we need to find the GCD of 16 and 28. The method known as Euclid\u2019s algorithm solves this problem by dividing two numbers, taking their remainder after division, and repeating the division step with one of the numbers and the remainder. Given two integers a and b, the algorithm proceeds according to this general process:<\/p>\n<ol>\n<li class=\"import-Normal\" style=\"text-indent: 0pt;\">Take two integers a and b, and let a be larger than b.<\/li>\n<li class=\"import-Normal\" style=\"text-indent: 0pt;\">Find the remainder of a \/ b, and let that number be r.<\/li>\n<li class=\"import-Normal\" style=\"text-indent: 0pt;\">If r is 0, b is the GCD; otherwise, repeat the process with b and r in place of a and b in step 1.<\/li>\n<\/ol>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The equations below illustrate this process. Here, let a equal 28, and let b equal 16:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">a \/ b<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">28 \/ 16=1 with remainder 12<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">16 \/ 12=1 with remainder 4<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">12 \/ 4=3 with remainder 0<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">Since the remainder is 0, the GCD is 4.<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">For the fraction 16\/28, dividing the denominator and the numerator by 4 gives the simplified fraction 4\/7. This is illustrated below:<\/p>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">(16 \/ 4) \/ (28 \/ 4) = 4 \/ 7.<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Before we start writing the algorithm, let us think about the base case and the recursive case. What signals the end of recursion? If the remainder of a divided by b is zero, this means that b is the greatest common divisor. This should be our base case. With any other inputs, the algorithm should make a recursive call with updated inputs. Let us examine one way to implement this algorithm. We will use the keyword <strong>mod<\/strong> to mean the remainder of two integers. For example, we will take the expression <strong>7 mod 3<\/strong> to be evaluated to the value 1. The keyword <strong>mod<\/strong> is a shortened version of the word \u201cmodulo,\u201d which is the operation that calculates integer remainders after division.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image21.png\" alt=\"image\" width=\"621.538477690289px\" height=\"101px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This process will continue to reduce a and b in sequence until the remainder is 0, ultimately finding the greatest common divisor. This provides a good example of a recursive numerical algorithm that has a practical use, which is for simplifying fractions.<\/p>\n<h2 class=\"import-Normal\">Recursive Find Minimum<\/h2>\n<p class=\"import-Normal\">Finding the minimum value in a collection of numbers can be formulated as a recursive algorithm. Let us use an array of integers for this algorithm. Our algorithm will use the helper and wrapper pattern, and it will use an extra parameter to keep track of the current minimum value. Let us begin by specifying the core algorithm as a helper function. Here, as in <strong>recReverse<\/strong>, we assume a <strong>length<\/strong> function can provide the length of the array:<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image22-1.png\" alt=\"image\" width=\"624px\" height=\"200.2px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">For this algorithm, our base case occurs when the recursive process reaches the last position of the array. This signals the end of recursion, and the <strong>currentMin<\/strong> value is returned. In the recursive case, we compare the value of the current minimum with the value at the current position. Next, a recursive call is made that uses the appropriate current minimum and increases the position.<\/p>\n<h1 class=\"import-Normal\">Recursive Algorithms and Complexity Analysis<\/h1>\n<p class=\"import-Normal\">Now that we have a better understanding of recursive algorithms, how can their complexity be evaluated? Computational complexity is usually evaluated in terms of time complexity and space complexity. How does the algorithm behave when the size of the input grows arbitrarily large with respect to runtime and memory space usage? Answering these questions may be a little different for recursive algorithms than for some other algorithms you may have seen.<\/p>\n<h2 class=\"import-Normal\">A Warm-Up, Nonrecursive Example: Powers of 2<\/h2>\n<p class=\"import-Normal\">Let us begin with the nonrecursive power-of-2 algorithm from the beginning of the chapter reprinted here:<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image7-1.png\" alt=\"image\" width=\"623.283569553806px\" height=\"87px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">For this algorithm, we observe a loop that starts at 1 and continues to n. This means that we have a number of steps roughly equal to n. This is a good clue that the time complexity is linear or O(n). For an n equal to 6, we could expand this procedure to the following sequence of 5 multiplications: 2 * 2 * 2 * 2 * 2 * 2. If we added 1 to n, we would have 6 multiplications for an n of 7. Actually, according to the algorithm as written, the correct sequence for an n equal to 6 would be 1 * 2 * 2 * 2 * 2 * 2 * 2. When n is 6, this sequence has exactly n multiplications counting the first multiplication by 1. This could be optimized away, but it is a good demonstration that with or without the optimization the time complexity would be O(n). As a reminder, O(n \u2212 1) is equivalent to O(n). The time complexity O(n) is also known as <strong>linear<\/strong> time complexity.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">For this algorithm, what is the space complexity? First, let us ask how many variables are used. Well, space is needed for the input parameter <strong>n<\/strong> and the <strong>product<\/strong> variable. Are any other variables needed? In a technical sense, perhaps some space would be needed to store the literal numerical values of 1 and 2, but this may depend on the specific computer architecture in use. We ignore these issues for now. That leaves the variables <strong>n<\/strong> and <strong>product<\/strong>. If the input parameter n was assigned the value of 10, how many variables would be needed? Just two variables would be needed. If n equaled 100, how many variables would be needed? Still, only two variables would be needed. This leads us to the conclusion that only a constant number of variables are needed regardless of the size of n. Therefore, the space complexity of this algorithm is O(1), also known as <strong>constant<\/strong> space complexity.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">In summary, this iterative procedure takes O(n) time and uses O(1) space to arrive at the calculated result. <strong>Note:<\/strong> This analysis is a bit of a simplification. In reality, the size of the input is proportional to log(n) of the value, as the number n itself is represented in approximately log<sub>2<\/sub>(n) bits. This detail is often ignored, but it is worth mentioning. The point is to build your intuition for Big-O analysis by thinking about how processes need to grow with larger inputs.<\/p>\n<h2 class=\"import-Normal\">Recursive Powers of 2<\/h2>\n<p class=\"import-Normal\">Now let us consider the power-of-2 recursive algorithm from earlier and analyze its complexity.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image23.png\" alt=\"image\" width=\"629px\" height=\"87.7979002624672px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">To analyze the complexity of this algorithm, let us examine some example input values. For an n equal to 1, the algorithm begins with <strong>recursivePowerOf2(1)<\/strong>. This call evaluates <strong>2 * recursivePowerOf2(1)<\/strong>. This expression then becomes 2 * 1, which is 2. For an n equal to 3, we have the following sequence:<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 36pt; margin-right: 36pt;\">recursivePowerOf2(3) -&gt; 2 * recursivePowerOf2(2)<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 * 2 * recursivePowerOf2(1)<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 * 2 * 2 * recursivePowerOf2(0)<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt; 2 * 2 * 2 * 1<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">So for an <strong>n<\/strong> equal to 3, we have three multiplications. From this expansion of the calls, we can see that this process ultimately resembles the iterative process in terms of the number of steps. We could imagine that for an n equal to 6, <strong>recursivePowerOf2(6)<\/strong> would expand into 2 * 2 * 2 * 2 * 2 * 2 * 1 equivalent to the iterative process. From this, we can reason that the time complexity of this recursive algorithm is O(n). This general pattern is sometimes called a <strong>linear recursive process<\/strong>.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The time complexity of recursive algorithms can also be calculated using a recurrence relation. Suppose that we let T(n) represent the actual worst-case runtime of a recursive algorithm with respect to the input n. We can then write the time complexity for this algorithm as follows:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">T(0) = 1<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n) = 1 + T(n \u2212 1).<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">This makes sense, as the time complexity is just the cost of one multiplication plus the cost of running the algorithm again with an input of n \u2212 1 (whatever that may be). When n is 0, we must return the value 1. This return action counts as a step in the algorithm.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Now we can use some substitution techniques to solve this recurrence relation:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=1 + T(n \u2212 1)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=1 + 1 + T(n \u2212 2)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=2 + T(n \u2212 2)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=2 + 1 + T(n \u2212 3)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=3 + T(n \u2212 3).<\/p>\n<\/div>\n<p class=\"import-Normal\">Here we start to notice a pattern. If we continue this out to T(n \u2212 n) = T(0), we can solve the relationship:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=n + T(n \u2212 n)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=n + T(0)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=n + 1.<\/p>\n<\/div>\n<p class=\"import-Normal\">We see that T(n) = n + 1, which represents the worst-case time complexity of the algorithm. Therefore, the algorithm\u2019s time complexity is O(n + 1) = O(n).<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Next, let us analyze the space complexity. You may try to approach this problem by checking the number of variables used in the recursive procedure that implements this algorithm. Unfortunately, recursion hides some of the memory demands due to the way procedures are implemented with the runtime stack. Though it appears that only one variable is used, every call to the recursive procedure keeps its own separate value for n. This leads to a memory demand that is proportional to the number of calls made to the recursive procedure. This behavior is illustrated in the following figure, which presents a representation of the runtime stack at a point in the execution of the algorithm. Assume that <strong>recursivePowerOf2(3)<\/strong> has been called inside main or another procedure to produce a result, and we are examining the stack when the last call to <strong>recursivePowerOf2(0)<\/strong> is made during this process.<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image24-1.png\" alt=\"Diagram of a call stack intended to show convey space needs during recursive calls\" width=\"797\" height=\"258\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.9<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The number of variables needed to calculate <strong>recursivePowerOf2(3)<\/strong> is proportional to the size of the input. The figure showing the call stack has a frame for each call starting with 3 and going down to 0. If our input increased, our memory demand would also increase. This observation leads to the conclusion that this algorithm requires O(n) space in the worst case.<\/p>\n<h2 class=\"import-Normal\">Tail-Call Optimization<\/h2>\n<p class=\"import-Normal\">In considering the two previous algorithms, we can compare them in terms of their time and space scaling behavior. The imperative <strong>powerOf2<\/strong> implementation uses a loop. This algorithm has a time complexity of O(n) and a space complexity of O(1). The <strong>recursivePowerOf2<\/strong> algorithm has a time complexity of O(n), but its space complexity is much worse at O(n). Fortunately, an optimization trick exists that allows recursive algorithms to reduce their space usage. This trick is known as tail-call optimization. If your language or compiler supports tail-call optimization, recursive algorithms can be structured to use the same amount of space as their corresponding iterative implementations. Actually, both algorithms would be considered iterative, as they iteratively update a fixed set of state variables. Let us examine a tail-call optimization example in greater detail.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">To fix our <strong>recursivePowerOf2<\/strong> implementation\u2019s space complexity issues, we will first slightly modify our algorithm. We will add a state variable that will hold the running product. This serves the same purpose as the product variable in our iterative loop implementation.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image25.png\" alt=\"image\" width=\"619px\" height=\"86.4020997375328px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">For this algorithm to work correctly, any external call should be made with <strong>product<\/strong> set to 1. This ensures that an exponent of n equal to 0 returns 1. This means it would be a good idea to wrap this algorithm in a wrapper function to avoid unnecessary errors when a programmer mistakenly calls the algorithm without <strong>product<\/strong> set to 1. This simple wrapper function is presented below:<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image26-1.png\" alt=\"image\" width=\"612px\" height=\"43.3500262467192px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">To understand how tail-call optimization works, let us think about what would happen on the stack when we made a call like <strong>recursivePowerOf2(1, 3)<\/strong> using our new algorithm (we will ignore the wrapper for this discussion). The stack without tail-call optimization would look like the following figure:<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image27.png\" alt=\"Call stack diagram of a recursive funciton which cannot leverage tail call optimization.\" width=\"757\" height=\"263\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.10<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">The key observation of tail-call optimization is that when the recursive call is at the tail end of the procedure (in this case, line 5), no information is needed from the current stack frame. This means that the current frame can simply be reused without consuming more memory. The following figure gives an illustration of <strong>recursivePowerOf2(1, 3)<\/strong> after the first recursive tail-call in the execution process.<\/p>\n<div class=\"textbox standard\">\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image28-1.png\" alt=\"Call stack diagram of a recursive funciton which can leverage tail call optimization\" width=\"757\" height=\"167\" \/><\/div>\n<p class=\"import-Normal\">Figure 2.11<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Using tail-call optimization, our new <strong>recursivePowerOf2<\/strong> algorithm has the same time complexity O(n) and space complexity O(1) as the loop-based iterative implementation. Keep in mind that tail-call optimization is a feature of either your interpreter or the compiler. You may wish to check if it is supported by your language (https:\/\/en.wikipedia.org\/wiki\/Tail_call#By_language).<\/p>\n<h2 class=\"import-Normal\">Powers of 2 in O(log n) Time<\/h2>\n<p class=\"import-Normal\">A clever algorithm is presented in Structure and Interpretation of Computer Programs (SICP, Abelson and Sussman, 1996) that calculates powers of any base in O(log n) time. Let us examine this algorithm to help us understand some recursive algorithms that are faster\u2014or rather, scale better\u2014than O(n) time.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">We will examine the same problem as above, calculating the nth power of 2. The key idea of this algorithm takes advantage of the fact that 2<sup>n<\/sup> = (2<sup>n\/2<\/sup>)<sup>2<\/sup> when n is even and 2 * 2<sup>n\u22121<\/sup> when n is odd. To implement this algorithm, we must first define two helper functions. One function will square an input number, and the other function will check if a number is even. We will define them here using <strong>mod<\/strong> to indicate the remainder after division.<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image29-1.png\" alt=\"image\" width=\"619.2px\" height=\"129px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">After defining these two functions, we will consider the bases and recursive cases for which we need to account. If n is 0, the algorithm should return 1 according to the mathematical definition of any base value raised to an exponent of 0. This will be one of our cases. Next, if the n is even, we will square the result of a recursive call to the algorithm passing the value of n\/2. This code is equivalent to our calculation of (2<sup>n\/2<\/sup>)<sup>2<\/sup>. Lastly, for the odd case, we will calculate 2 times the result of a recursive call that passes the value of n \u2212 1. This code handles the odd case equivalent to 2 * 2<sup>n\u22121<\/sup> and sets up the use of our efficient even exponent case. The algorithm is presented below:<\/p>\n<div class=\"wp-nocaption aligncenter\"><img class=\"aligncenter\" src=\"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-content\/uploads\/sites\/57\/2023\/08\/image30-1.png\" alt=\"image\" width=\"624px\" height=\"116.333333333333px\" \/><\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Let us think about the process this algorithm uses to calculate 2<sup>9<\/sup>. This process starts with a call to <strong>fastPowerOf2(9)<\/strong>. Since 9 is odd, we would multiply <strong>2 * fastPowerOf2(8)<\/strong>. This expression then expands to <strong>2 * square(fastPowerOf2(4))<\/strong>. Let us look at this in more detail.<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 36pt; margin-right: 36pt;\">fastPowerOf2(9)-&gt;2 * fastPowerOf2(8)<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(fastPowerOf2(4))<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(square(fastPowerOf2(2)))<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(square(square(fastPowerOf2(1))))<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(square(square(2 * fastPowerOf2(0))))<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(square(square(2 * 1)))<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(square(4))<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * square(16)<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;2 * 256<\/p>\n<p class=\"import-Normal\" style=\"margin-left: 54pt; margin-right: 36pt;\">-&gt;512<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">It may not be clear that this algorithm is faster than the previous <strong>recursivePowerOf2<\/strong>, which was bounded by O(n). Considering the linear calculation of 2<sup>9<\/sup> would look like this: 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 with 9 multiplications. For this algorithm, we could start thinking about the calculation that is equivalent to <strong>2 * square(square(square(2 * 1)))<\/strong>. Our first multiplication is 2 * 1. Next, the <strong>square<\/strong> procedure multiplies 2 * 2 to get 4. Then 4 is squared, and then 16 is squared for 2 more multiplications. Finally, we get 2 * 256, giving the solution of 512 after only 5 multiply operations. At least for an n of 9, <strong>fastPowerOf2<\/strong> uses fewer multiply operations. From this, we could imagine that for larger values of n, the <strong>fastPowerOf2<\/strong> algorithm would yield even more savings with fewer total operations compared to the linear algorithm.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Let us now examine the time complexity of <strong>fastPowerOf2<\/strong> using a recurrence relation. The key insight is that roughly every time the recursive algorithm is called, n is cut in half. We could model this as follows: Let us assume that there is a small constant number of operations associated with each call to the recursive procedure. We will represent this as c. Again, we will use the function T(n) to represent the worse-case number of operations for the algorithm. So for this algorithm, we have T(n) = c + T(n\/2). Let us write this and the base case as a recurrence relation:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">T(0)=c<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=c + T(n\/2).<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">To solve this recurrence problem, we begin by making substitutions and looking for a pattern:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=c + T(n\/2)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">\u00a0\u00a0\u00a0=c + c + T(n\/4)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">\u00a0\u00a0\u00a0=c + c + c + T(n\/8).<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">We are beginning to see a pattern, but it may not be perfectly clear. The key is in determining how many of those constant terms there will be once the expression of T(n\/x) becomes 1 or 0. Let us rewrite these terms in a different way:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=c + T(n\/2<sup>1<\/sup>)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">\u00a0\u00a0\u00a0=2c + T(n\/2<sup>2<\/sup>)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">\u00a0\u00a0\u00a0=3c + T(n\/2<sup>3<\/sup>).<\/p>\n<\/div>\n<p class=\"import-Normal\">Now we seek a pattern that is a little clearer:<\/p>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">T(n)=k * c + T(n\/2<sup>k<\/sup>).<\/p>\n<\/div>\n<p class=\"import-Normal\">So when will n\/2<sup>k<\/sup> be 1?<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">We can solve for k in the following equation:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">n\/2<sup>k<\/sup>=1<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">2<sup>k<\/sup> * (n\/2<sup>k<\/sup>)=2<sup>k<\/sup> * 1<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">n=2<sup>k<\/sup>.<\/p>\n<\/div>\n<p class=\"import-Normal\">Now taking the log<sub>2<\/sub> of each side gives the following:<\/p>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">log<sub>2<\/sub> n=k.<\/p>\n<\/div>\n<p class=\"import-Normal\">Now we can rewrite the original formula:<\/p>\n<div class=\"textbox standard\">\n<p style=\"text-align: center;\">T(n)=log<sub>2<\/sub> n * c + T(1).<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">According to our algorithm, with <strong>n<\/strong> equal to 1, we use the odd case giving 2 * <strong>fastPowerOf2(0)<\/strong> = 1. So we could reason that T(1) = 2c. Finally, we can remove the recursive terms and with a little rewriting arrive at the time complexity:<\/p>\n<div class=\"textbox standard\">\n<p class=\"import-Normal\" style=\"text-align: center;\">T(n)=log<sub>2<\/sub> n * c + T(1)<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=log<sub>2<\/sub> n * c + 2c<\/p>\n<p class=\"import-Normal\" style=\"text-align: center;\">=c * (log<sub>2<\/sub> n + 2).<\/p>\n<\/div>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Therefore, our asymptotic time complexity is O(log n)<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">Here we have some constants and lower-order terms that lead us to a time complexity of O(log n). This means that the scaling behavior of <strong>fastPowerOf2<\/strong> is much, much better than our linear version. For reference, suppose n was set to 1,000. A linear algorithm would take around 1,000 operations, whereas an O(log n) algorithm would only take around 20 operations.<\/p>\n<p class=\"import-Normal\" style=\"text-indent: 36pt;\">As for space complexity, this algorithm does rely on a nested call that needs information from previous executions. This requirement is due to the square function that needs the result of the recursive call to return. This implementation is not tail-recursive. In determining the space complexity, we need to think about how many nested calls need to be made before we reach a base case to signal the end of recursion. For a process like this, all these calls will consume memory by storing data on the runtime stack. As n is divided each time, we will reach a base case after O(log n) recursive calls. This means that in the worst case, the algorithm will have O(log n) stack frames taking up memory. Put simply, its space complexity is O(log n).<\/p>\n<p>&nbsp;<\/p>\n<div class=\"textbox textbox--exercises\">\n<header class=\"textbox__header\">\n<p class=\"textbox__title\">Exercises<\/p>\n<\/header>\n<div class=\"textbox__content\">\n<ol class=\"legal\">\n<li>Write a recursive function like that of <strong>powerOf2<\/strong> called \u201cpow\u201d that takes a <strong>base<\/strong> and <strong>exponent<\/strong> variables and computes the value of <strong>base<\/strong> raised to the <strong>exponent<\/strong> power for any integer base &gt;= 1 and any integer exponent &gt;= 0.<\/li>\n<li>The sequence {0, 1, 3, 6, 10, 15, 21, 28, \u2026 } gives the sequence of triangular numbers.\n<ol>\n<li>Give a recursive definition of the triangular numbers (starting with n = 0).<\/li>\n<li>Give a recursive algorithm for calculating the nth triangular number.<\/li>\n<\/ol>\n<\/li>\n<li>Modify the <strong>recMin<\/strong> algorithm to create a function called <strong>recMinIndex<\/strong>. Your algorithm should return the index of the minimum value in the array rather than the minimum value itself. <strong>Hint:<\/strong> You should add another parameter to the helper function that keeps track of the minimum value\u2019s index.<\/li>\n<li>Write an algorithm called <strong>simplify<\/strong> that prints the simplified output of a fraction. Have the procedure accept two integers representing the numerator and denominator of a fraction. Have the algorithm print a simplified representation of the fraction. For example, <strong>simplify(8, 16)<\/strong> should print \u201c1 \/ 2.\u201d Use the GCD algorithm as a subroutine in your procedure.<\/li>\n<li>Implement the three <strong>powerOf2<\/strong> algorithms (iterative, recursive, and <strong>fastPowerOf2<\/strong>) in your language of choice. Calculate the runtime of the different algorithms, and determine which algorithms perform best for which values of n. Using your data, create a \u201csuper\u201d algorithm that checks the size of n and calls the most efficient algorithm depending on the value of n.<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<p>&nbsp;<\/p>\n<div class=\"textbox textbox--key-takeaways\">\n<header class=\"textbox__header\">\n<p class=\"textbox__title\">References<\/p>\n<\/header>\n<div class=\"textbox__content\">\n<p class=\"import-Normal hanging-indent\">Abelson, Harold, and Gerald Jay Sussman. <em>Structure and Interpretation of Computer Programs<\/em>. The MIT Press, 1996.<\/p>\n<\/div>\n<\/div>\n<p>&nbsp;<\/p>\n","protected":false},"author":13,"menu_order":2,"template":"","meta":{"pb_show_title":"on","pb_short_title":"","pb_subtitle":"","pb_authors":[],"pb_section_license":""},"chapter-type":[],"contributor":[],"license":[],"part":3,"_links":{"self":[{"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/pressbooks\/v2\/chapters\/287"}],"collection":[{"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/pressbooks\/v2\/chapters"}],"about":[{"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/wp\/v2\/types\/chapter"}],"author":[{"embeddable":true,"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/wp\/v2\/users\/13"}],"version-history":[{"count":25,"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/pressbooks\/v2\/chapters\/287\/revisions"}],"predecessor-version":[{"id":873,"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/pressbooks\/v2\/chapters\/287\/revisions\/873"}],"part":[{"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/pressbooks\/v2\/parts\/3"}],"metadata":[{"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/pressbooks\/v2\/chapters\/287\/metadata\/"}],"wp:attachment":[{"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/wp\/v2\/media?parent=287"}],"wp:term":[{"taxonomy":"chapter-type","embeddable":true,"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/pressbooks\/v2\/chapter-type?post=287"},{"taxonomy":"contributor","embeddable":true,"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/wp\/v2\/contributor?post=287"},{"taxonomy":"license","embeddable":true,"href":"https:\/\/pressbooks.palni.org\/anopenguidetodatastructuresandalgorithms\/wp-json\/wp\/v2\/license?post=287"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}