Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Janice Lichtman - Recursion Tracing #25

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 79 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
# Recursion Problems

## Definitions
Define the following:
Define the following:

- Recursion
- Recursive Case
- Base Case
- Activation Chain/Stack
- Activation Record/Call
- Infinite Recursion/Stack Overflow/Stack too deep
- Tail Recursion
- Recursion:
A method that calls itself. (In general, any self-referential process or definition)
- Recursive Case:
The case in a recursive method, where the recursion happens (ie where the method itself is called.)
- Base Case:
The case in a recursive method, where no recursion happens.
Generally successive terations of the recursive case bring you closer to the base case, and the base case is where the method evaluation finally terminates.
- Activation Chain/Stack:
The entire chain of successive iterations of the recursive case and the eventual base case that are evaluated when the method is invoked.
- Activation Record/Call:
A single evaluation of the recursive case in the process of evaluating a recursive method (ie one step in the activation chain/stack.)
- Infinite Recursion/Stack Overflow/Stack too deep:
If the recursive case does not bring the method evaluation closer to the base case on successive iterations, then the recursion will continue 'infinitely'. In practice, it will continue until the allotted memory is full, and a 'stack overflow'/'stack too deep' error will be thrown, terminating the process.
- Tail Recursion:
Tail Recursion is where calculations are made at every step in the recursive case, and the result is then passed to the next call of the method. It is different from traditional recursion where the full chain of recursive calls must be made before the calculations begin.

In other words, in Traditional Recursion, the full chain of recursive calls are made and held in the stack. Then, once the base case is reached, calculations begin and the results for each record are passed back up the chain.
In Tail Recursion, however, calculations are made along the way and only the results are passed to successive recursive cases. (Ie,in Tail Recursion, no calculations happen on the return line).

The benefit of Tail Recursion, in languages that support it, is that the compiler does not need to keep track of the entire activation chain/stack. Instead, at each recursive step, it can simply replace the data and reuse the 'current stack frame'.

## Tracing through a recursive method

Expand All @@ -24,9 +37,10 @@ def mystery1(n)
end
```

- What is mystery1(5)?
- What is mystery1(10)?
- What is mystery1(0)?
- What is mystery1(5)? 15
- What is mystery1(10)? 55
- What is mystery1(0)? Infinite Recursion-
SystemStackError: stack level too deep

### Trace #2
```
Expand All @@ -39,11 +53,25 @@ def mystery2(n)
end
```

- What is mystery2(123)?
- What is mystery2(9005)?
- What is mystery2(-123)?
- What is mystery2(123)? 6
- What is mystery2(9005)? 14
- What is mystery2(-123)? -123
- _Added Fun: How could we make `mystery2(-123)` work the way we might expect it to work instead of the way it does?_

We could "ignore the negative sign" while we sum the digits and then replace it at the end. This could be done as follows:

def mystery2B(n)
if n < 10 && n > -10
return n
elsif n >= 10
return (n%10) + mystery2(n/10)
else m = n.abs
a = (m%10) + mystery2(m/10)
return -a
end
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it works. I also just posted an alternative solution that is perhaps more readable.



### Trace #3
```
def mystery3(n)
Expand All @@ -60,9 +88,9 @@ def mystery3(n)
end
```

- What is mystery3(1)?
- What is mystery3(13)?
- What is mystery3(-6)?
- What is mystery3(1)? 100
- What is mystery3(13)? 100
- What is mystery3(-6)? 200

### Trace #4
```
Expand All @@ -75,9 +103,9 @@ def mystery4(b,e)
end
```

- What is mystery4(10,2)?
- What is mystery4(4,3)?
- What is mystery4(5,0)?
- What is mystery4(10,2)? 100
- What is mystery4(4,3)? 64
- What is mystery4(5,0)? 1

### Trace #5
```
Expand All @@ -90,10 +118,24 @@ def mystery5(s)
end
```

- What is mystery5("hi")?
- What is mystery5("")?
- What is mystery5("Hi, there!")?
- What is mystery5("hi")? **
- What is mystery5("")? "" (ie, empty string)
- What is mystery5("Hi, there!")? **********

- _Added Fun: How could we make only alphabetic characters to be changed to stars?_
def mystery5C(s)
alpha_all = ("A".."Z").to_a.concat ("a".."z").to_a
if s.length == 0
return ""
else
if alpha_all.include?(s[0])
return "*" + mystery5C(s[1..-1])
else
return mystery5C(s[1..-1])
end
end
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it works. I did post another solution to consider.

One thing is to figure out if you think I intended mystery5("Hi, there!") to produce "*******" or "**, *****!"

I intended the latter, but didn't specify so you+others assumed and wrote solutions for the former.


### Trace #6
```
Expand All @@ -110,7 +152,20 @@ def mystery6(s)
end
```

- What is mystery6("goodnight moon")?
- What is mystery6("goodnight moon")?
" moon goodnight" (note: includes initial underscore)
- What is mystery6("Ada Developers Academy")?
" Academy Developers Ada"
- What is mystery6("Hi, there!")?
" there! Hi,"

- _Added Fun: How could we make the reversal happen by letter, instead of by word (i.e. Make it so that mystery6("goodnight moon") returned "noom thgindoog")?_


def mystery6B(s)
if s == nil || s.length == 0
return ""
else
return mystery6B(s[1..-1]) + s[0]
end
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 my solution too. Though I wrote the base case differently, they are essentially the same. I didn't account for nil though.

62 changes: 62 additions & 0 deletions mystery-methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ def mystery1(n)
end
end


def mystery2(n)
if n < 10
return n
Expand All @@ -14,6 +15,33 @@ def mystery2(n)
end
end

def mystery2B(n)
if n < 10 && n > -10
return n
elsif n >= 10
return (n%10) + mystery2(n/10)
else m = n.abs
a = (m%10) + mystery2(m/10)
return -a
end
end

def mystery2C(n)
if n>=0
if n < 10
return n
else
return (n%10) + mystery2(n/10)
end
else
if n > -10
return n
else m = n.abs
return -((m%10) + mystery2(m/10))
end
end
end

def mystery3(n)
if n == 0
return 100
Expand Down Expand Up @@ -43,6 +71,31 @@ def mystery5(s)
end
end

#Changing only alphabetic characters to * using RegEx (regular expression)
def mystery5B(s)
s.gsub!(/[^a-zA-Z]/, '')
if s.length == 0
return ""
else
return "*" + mystery5(s[1..-1])
end
end

#Changing only alphabetic characters to * without RegEx
def mystery5C(s)
alpha_all = ("A".."Z").to_a.concat ("a".."z").to_a
if s.length == 0
return ""
else
if alpha_all.include?(s[0])
return "*" + mystery5C(s[1..-1])
else
return mystery5C(s[1..-1])
end
end
end


def mystery6(s)
if s == nil || s.length == 0
return ""
Expand All @@ -54,3 +107,12 @@ def mystery6(s)
return mystery6(s[(space+1)..-1]) + " " + s[0...space]
end
end


def mystery6B(s)
if s == nil || s.length == 0
return ""
else
return mystery6B(s[1..-1]) + s[0]
end
end
7 changes: 7 additions & 0 deletions sandbox.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'pry'

alpha_all = ("A".."Z").to_a.concat ("a".."z").to_a
print alpha_all

s="hi there"
binding.pry