PR2EN11: Stack and recursion

Lab materials

Lab tasks

In this lab there are two base tasks, one completely independent advanced task for recursion and one advanced task as an extension to the stack task.

Task 1: Set of recursion tasks

As the first task, you need to create three recursive programs (parts 1, 2 and 3). The task can only be presented once all three are done!

NB! The recursions are extremely simple, avoid looking for solutions on the internet!

In the beginning of the lesson, we’ll create an example of a factorial task solved recursively!

Requirements
  • You can make the solution as one file with three recursions or as three separate programs. Examples are provided as separate programs.
  • In all cases, the programs must support positive integers as input. Negative input either has a defined base case or will cause an error.
  • Input can be asked inside of the application or read as a command line argument.
  • Iterative solutions are not permitted! All three parts must be solved recursively
  • Only present your task once all three parts are completed.
Part 1: Sum

Create an application that finds the sum of all positive integers until the entered integer. Negative argument for the recursive function returns the sum as 0 (no positive numbers to add, base case)

Part 2: Power

Create an application that allows you to take x to the power of y (xy). Using the math library and built in power function is not allowed.

NB! Even though you only need to create the solution for positive integers, you can also try to expand to negative values.

Part 3: Fibonacci sequence

Create an application that finds the n-th Fibonacci number. The fibonacci numbers are calculated as the sum of two previous fibonacci numbers  fibx = fibx – 1 + fibx – 2. Compared to the previous recursions, Fibonacci sequence requires two base cases.

Fibonacci numbers are  0, 1, 1, 2, 3, 5, 8, 13, 21, …,

Did you notice how long it took to find the last value? This is expected in the lab and you don’t need to fix anything, however you should understand why this happened! If not, think or ask!

All 3 parts are done, now present your lab!

You can time the execution of your program using the  time  program. I’ve put the comparison of two different solutions for Fibonacci below. The second one uses tail-recursion. You can read about it on your own if necessary!

Task 2: Stack

In this task, we will create a menu program to demonstrate some of the stack functions. The lab task is demonstrative only and is intended to support the dynamic memory allocation studied before – due to the added complexity of this, the benefits of speed are unfortunately diminished.

In the beginning of the lesson, we will create a partial solution with the Push() function.

Requirements
  • Create a menu structure – the user must be able to select the desired operation.
  • Create Pop() and Peek() functions
    • Pop() removes the topmost element from the stack and returns the value.
    • Peek() returns the topmost element from the stack, but does not remove it.
  • The functions you create are not allowed to display the values themselves!  Print the values on the screen once they are returned back to the menu!
  • NB! In the base variant, you are allowed to reserve a special value to be returned in the case of stack underflow, so that the illegal value wouldn’t be displayed. This is not allowed in the advanced version of this task.
  • Depending on the function, implement either underflow or overflow detection!
  • Pay attention to the situation when all the elements are removed from the stack – do not use realloc for 0 bytes, use the free() function!
Debugging function for the stack

In order to get a bit better understanding of the stack contents, we’ll provide a debugging function. In reality, this kind of function goes against the limitations of the stack and may also not even be possible due to the implementation specifics!

Testing

During testing, pay extra attention to

  • stack overflow
  • stack underflow
  • freeing the data after last element is popped.
  • memory leak when the program exits when there are still values in the stack
Click me to see the output

Advanced task 1: practical use case for recursion

This advanced task is given to you as a description of an algorithm. This is a completely independent task, that is not related to the original lab task solution!

NB! The variables in the description are given more to the likes of mathematicians (single letters). Use descriptive variable names when creating your program as is more suited for programming.

Given search key K  and an array A  of n  integers A0, A1, … , An – 1 sorted such that A0 ≤ A1≤ … ≤ An – 1 use the following algorithm to find if K ∈ A

  1. Set lowIndex L  to   and highIndex H  to n − 1 .
  2. Call the recursive function using 4 arguments – A, L, H, K .
    • If L > H , the search terminates as unsuccessful – return 0
    • Set m  (the position of the middle element) to the floor of (L + H)  /  2
    • If Am < K, set L  to m + 1 , call recursion again
    • If Am > K, set H  to m − 1 , call recursion again
    • If Am = K, the search was successful – return 1

Once the task is complete, prepare the answer to the following questions. Once ready, present your task!

  • Time complexity – compare the given algorithm and conventional linear search. How many comparisons do you need to find the result from an array that has
    • 16 members
    • 256 members
    • 100 000 members
  • Give an esimate toe the complexity – e.g. constant, logarithmic, linear, exponential (https://www.bigocheatsheet.com)
  • If the array wouldn’t be sorted, would the algorithm still work?

Advanced task 2: improving and extending the stack

In this task, we will add a two extra functions and make it a bit more universal than the original solution.

Requirements

  • Add the following functions to your stack
    • Duplicate()
    • Swap()
  • These functions are only allowed to use the original Push(), Pop() and Peek() functions internally to access the stack!
  • Change your Pop() and Peek()  functions in a way that the following would apply
    • Stack must allow any integers (reserved values are not allowed!)
    • In the case of an underflow during popping from the stack, you can only provide a warning message, but not display the value!
  • Note: You’ll likely need to adjust your Push() function as well to accomodate the additional functions

Testing

These would be the important edge cases to test for in addition to the normal operation

  • Pop(), when the stack is empty (do not display any value)
  • Duplicate(), when the stack is empty
  • Duplicate(), when the stack is full
  • Swap(), when the stack si empty
  • Swap(), when the stack only has one member

After this class, you should

  • Know what a recursion is, including recursive functions and data structures
  • Know how to write simple recursions
  • Know about the existence of a tail recursion
  • Know about the good and bad that recursions bring to the table
  • Know use cases for recursions
  • Know what an abstract data structure means
  • Know what is a stack and what are its properties
  • Know the use cases for stacks
  • Know how to create a stack and its mandatory functions

Additional materials