Lecture10 Slides
Lecture10 Slides
C++ basics
Implementation
User/client
vectors + grids arrays
dynamic memory
stacks + queues
management
sets + maps linked data structures
real-world
Diagnostic algorithms
C++ basics
Implementation
User/client
vectors + grids arrays
dynamic memory
stacks + queues
management
sets + maps linked data structures
real-world
Diagnostic algorithms
● Recursion has two main parts: the base case and the recursive case.
○ Base case: Simplest form of the problem that has a direct answer.
○ Recursive case: The step where you break the problem into a smaller, self-similar task.
Recursion Review
● Recursion is a problem-solving technique in which tasks are completed by
reducing them into repeated, smaller tasks of the same form.
● Recursion has two main parts: the base case and the recursive case.
● The solution will get built up as you come back up the call stack.
○ The base case will define the “base” of the solution you’re building up.
○ Each previous recursive call contributes a little bit to the final solution.
○ The initial call to your recursive function is what will return the completely constructed answer.
Recursion Review
● Recursion is a problem-solving technique in which tasks are completed by
reducing them into repeated, smaller tasks of the same form.
● Recursion has two main parts: the base case and the recursive case.
● The solution will get built up as you come back up the call stack.
● When solving problems recursively, look for self-similarity and think about
what information is getting stored in each stack frame.
Recursion Review
● Recursion is a problem-solving technique in which tasks are completed by
reducing them into repeated, smaller tasks of the same form.
● Recursion has two main parts: the base case and the recursive case.
● The solution will get built up as you come back up the call stack.
● When solving problems recursively, look for self-similarity and think about
what information is getting stored in each stack frame.
Example:
isPalindrome()
Write a function that returns if a string is a palindrome
A string is a palindrome if it reads the same both forwards and backwards:
● isPalindrome(“level”) → true
● isPalindrome(“racecar”) → true
● isPalindrome(“step on no pets”) → true
● isPalindrome(“high”) → false
● isPalindrome(“hi”) → false
● isPalindrome(“palindrome”) → false
● isPalindrome(“X”) → true
● isPalindrome(“”) → true
Approaching recursive problems
● Look for self-similarity.
● Ask yourself:
○ What is the base case? (What is the simplest case?)
○ What is the recursive case? (What pattern of self-similarity do you see?)
Discuss:
What are the base and
recursive cases?
(breakout rooms)
isPalindrome()
● Look for self-similarity: racecar
isPalindrome()
● Look for self-similarity: racecar
○ Look at the first and last letters of “racecar” → both are ‘r’
isPalindrome()
● Look for self-similarity: racecar
○ Look at the first and last letters of “racecar” → both are ‘r’
○ Check if “aceca” is a palindrome:
isPalindrome()
● Look for self-similarity: racecar
○ Look at the first and last letters of “racecar” → both are ‘r’
○ Check if “aceca” is a palindrome:
■ Look at the first and last letters of “aceca” → both are ‘a’
■ Check if “cec” is a palindrome:
isPalindrome()
● Look for self-similarity: racecar
○ Look at the first and last letters of “racecar” → both are ‘r’
○ Check if “aceca” is a palindrome:
■ Look at the first and last letters of “aceca” → both are ‘a’
■ Check if “cec” is a palindrome:
● Look at the first and last letters of “cec” → both are ‘c’
● Check if “e” is a palindrome:
isPalindrome()
● Look for self-similarity: racecar
○ Look at the first and last letters of “racecar” → both are ‘r’
○ Check if “aceca” is a palindrome:
■ Look at the first and last letters of “aceca” → both are ‘a’
■ Check if “cec” is a palindrome:
● Look at the first and last letters of “cec” → both are ‘c’
● Check if “e” is a palindrome:
○ Base case: “e” is a palindrome
isPalindrome()
● Look for self-similarity: racecar
○ Look at the first and last letters of “racecar” → both are ‘r’
○ Check if “aceca” is a palindrome:
■ Look at the first and last letters of “aceca” → both are ‘a’
■ Check if “cec” is a palindrome:
● Look at the first and last letters of “cec” → both are ‘c’
● Check if “e” is a palindrome:
○ Base case: “e” is a palindrome
string
if<<(s.length()
noboolalpha< <<
2) endl;
{
return true;
“racecar”
return 0;
} } else {
if (s[0] != s[s.length() - 1]) {
s
return false;
}
return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< <<
2) endl;
{
return true;
“racecar”
return 0;
} } else {
if (s[0] != s[s.length() - 1]) {
s
return false;
}
return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< <<
2) endl;
{
return true;
“racecar”
return 0;
} } else {
if (s[0] != s[s.length() - 1]) {
s
return false;
}
return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< <<
2) endl;
{
return true;
“racecar”
return 0;
} } else {
if (s[0] != s[s.length() - 1]) {
s
return false;
}
return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< <<
2) endl;
{
return true;
“racecar”
return 0;
} } else {
if (s[0] != s[s.length() - 1]) {
s
return false;
}
return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< << 2) endl;
{
bool isPalindrome
return true; (string s) { “racecar”
return 0;
string
if (s.length() < 2) {
} } else {
if return true;
(s[0] != s[s.length() - 1]) {
s“aceca”
} else return
{ false; s
} if (s[0] != s[s.length() - 1]) {
return false;
return isPalindrome(s.substr(1, s.length() - 2));
} }
} return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< << 2) endl;
{
bool isPalindrome
return true; (string s) { “racecar”
return 0;
string
if (s.length() < 2) {
} } else {
if return true;
(s[0] != s[s.length() - 1]) {
s“aceca”
} else return
{ false; s
} if (s[0] != s[s.length() - 1]) {
return false;
return isPalindrome(s.substr(1, s.length() - 2));
} }
} return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< << 2) endl;
{
bool isPalindrome
return true; (string s) { “racecar”
return 0;
string
if (s.length() < 2) {
} } else
bool
{
ifisPalindrome
return
(s[0] != true; (string s)-{1]) {
s[s.length()
s“aceca”
string
if (s.length() < 2) {
} else {
return false; s “cec”
} if return
(s[0] !=true;
s[s.length() - 1]) {
} elseisPalindrome(s.substr(1,
return {
return false; s.length() s- 2));
} } if (s[0] != s[s.length() - 1]) {
} return false;
return isPalindrome(s.substr(1, s.length() - 2));
} }
} return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< << 2) endl;
{
bool isPalindrome
return true; (string s) { “racecar”
return 0;
string
if (s.length() < 2) {
} } else
bool
{
ifisPalindrome
return
(s[0] != true; (string s)-{1]) {
s[s.length()
s“aceca”
string
if (s.length() < 2) {
} else {
return false; s “cec”
} if return
(s[0] !=true;
s[s.length() - 1]) {
} elseisPalindrome(s.substr(1,
return {
return false; s.length() s- 2));
} } if (s[0] != s[s.length() - 1]) {
} return false;
return isPalindrome(s.substr(1, s.length() - 2));
} }
} return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< << 2) endl;
{
bool isPalindrome
return true; (string s) { “racecar”
return 0;
string
if (s.length() < 2) {
} } else
bool
{
ifisPalindrome
return
(s[0] != true; (string s)-{1]) {
s[s.length()
s“aceca”
string
if (s.length() < 2) {
} else
bool
{
return false;
isPalindrome (string s)-{1]) { s “cec”
} if return
(s[0] != true;
s[s.length()
string
if (s.length() < 2) {
} else
return {
return false;
isPalindrome(s.substr(1, s.length() s- “e” 2));
} if return
(s[0] true;
!= s[s.length() - 1]) {
}
}
} elseisPalindrome(s.substr(1,
return {
return false; s.length() s- 2));
} } if (s[0] != s[s.length() - 1]) {
} return false;
return isPalindrome(s.substr(1, s.length() - 2));
} }
} return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< << 2) endl;
{
bool isPalindrome
return true; (string s) { “racecar”
return 0;
string
if (s.length() < 2) {
} } else
bool
{
ifisPalindrome
return
(s[0] != true; (string s)-{1]) {
s[s.length()
s“aceca”
string
if (s.length() < 2) {
} else
bool
{
return false;
isPalindrome (string s)-{1]) { s “cec”
} if return
(s[0] != true;
s[s.length()
string
if (s.length() < 2) {
} else
return {
return false;
isPalindrome(s.substr(1, s.length() s- “e” 2));
} if return
(s[0] true;
!= s[s.length() - 1]) {
}
}
} elseisPalindrome(s.substr(1,
return {
return false; s.length() s- 2));
} } if (s[0] != s[s.length() - 1]) {
} return false;
return isPalindrome(s.substr(1, s.length() - 2));
} }
} return isPalindrome(s.substr(1, s.length() - 2));
}
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< << 2) endl;
{
bool isPalindrome
return true; (string s) { “racecar”
return 0;
string
if (s.length() < 2) {
} } else
bool
{
ifisPalindrome
return
(s[0] != true; (string s)-{1]) {
s[s.length()
s“aceca”
string
if (s.length() < 2) {
} else {
return false; s “cec”
} if return
(s[0] !=true;
s[s.length() - 1]) {
} elseisPalindrome(s.substr(1,
return {
return false; s.length() s- 2));
} } if (s[0] != s[s.length() - 1]) {
} return false;
return isPalindrome(s.substr(1, s.length() - 2));
} }
} return isPalindrome(s.substr(1, s.length() - 2));
} true
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< << 2) endl;
{
bool isPalindrome
return true; (string s) { “racecar”
return 0;
string
if (s.length() < 2) {
} } else {
if return true;
(s[0] != s[s.length() - 1]) {
s“aceca”
} else return
{ false; s
} if (s[0] != s[s.length() - 1]) {
return false;
return isPalindrome(s.substr(1, s.length() - 2));
} }
} return isPalindrome(s.substr(1, s.length() - 2));
} true
}
isPalindrome() in action
int main() {
cout << boolalpha <<
bool isPalindrome (string s) {
isPalindrome(“racecar”)
string
if<<(s.length()
noboolalpha< <<
2) endl;
{
return true;
“racecar”
return 0;
} } else {
if (s[0] != s[s.length() - 1]) {
s
return false;
}
return isPalindrome(s.substr(1, s.length() - 2));
} true
}
isPalindrome() in action
int main() {
Prints true!
cout << boolalpha <<
isPalindrome(“racecar”)
<< noboolalpha << endl;
return 0;
}
How can we use visual
representations to understand
recursion?
Self-Similarity
Self-Similarity
● Solving problems recursively and
analyzing recursive phenomena
involves identifying self-similarity
Self-Similarity
● Solving problems recursively and
analyzing recursive phenomena
involves identifying self-similarity
http://recursivedrawing.com/
Announcements
Announcements
● Assignment 1 grades and commented feedback will be released on Paperless
by the end of the day today.
● Make sure to check out our weekly announcement posts on Ed – there's lot of
important info contained there!
● We will abstract away almost all of the complexity for you via provided helper
functions.
○ There are two main classes/components of the library you need to know: GWindow and GPoint
GWindow
● A GWindow is an abstraction for the
graphical window upon which we
will do all of our drawing.
increasing x
(0,0)
GWindow
● A GWindow is an abstraction for the
graphical window upon which we
will do all of our drawing.
The window defines a coordinate
increasing y
●
system of x-y values
○ The top left corner is (0, 0)
○ The bottom right corner is
(windowWidth, windowHeight)
increasing x
(0,0)
GWindow
(200,100)
● A GWindow is an abstraction for the
graphical window upon which we
will do all of our drawing.
The window defines a coordinate
increasing y
●
system of x-y values (400,250)
○ The top left corner is (0, 0)
○ The bottom right corner is
(windowWidth, windowHeight)
● All lines and shapes drawn on the
window are defined by their (x,y)
coordinates
increasing x
(0,0)
GPoint
● A GPoint is a handy way to bundle up
the x-y coordinates for a specific point GPoint (x,y)
in the window.
○ Very similar in functionality to the
increasing y
GridLocation struct we learned about
before!
increasing x
(0,0)
GPoint
(200,100)
● A GPoint is a handy way to bundle up
the x-y coordinates for a specific point
in the window.
midpoint
○ Very similar in functionality to the
increasing y
GridLocation struct we learned about
before! (400,250)
GPoint midpoint = {
(topLeft.getX() + bottomRight.getX())/ 2,
(topLeft.getY() + bottomRight.getY())/ 2
};
Cantor Set example
Cantor Set
● The first fractal we will code is called the "Cantor" fractal, named after the
late-19th century German mathematician Georg Cantor.
● The Cantor fractal is a set of lines where there is one main line, and below that
there are two other lines: each ⅓ of the width of the original line, with one on
the left and one on the right (with a ⅓ separation of whitespace between them)
An order-1 carpet is
subdivided into
eight order-0
carpets arranged in
this grid pattern
An order-2 Sierpinski Carpet
???
Practice and Discuss:
Draw the order-2 Sierpinski
carpet. What are the base and
recursive cases that define this
fractal?
(breakout rooms)
An order-2 Sierpinski Carpet
An order-2 Sierpinski Carpet
Sierpinski Carpet Formalized
● Base Case (order-0)
○ Draw a filled square at the
appropriate location
Sierpinski Carpet Formalized
● Base Case (order-0)
○ Draw a filled square at the
appropriate location
● Recursive Case (order-n, n ≠ 0)
○ Draw 8 order n-1 Sierpinski
carpets, arranged in a 3x3 grid,
omitting the center location
Sierpinski Carpet Formalized
● Base Case (order-0)
○ Draw a filled square at the (0,0) (0,1) (0,2)
appropriate location
● Recursive Case (order-n, n ≠ 0)
○ Draw 8 order n-1 Sierpinski
carpets, arranged in a 3x3 grid, (1,0) (1,2)
omitting the center location
pretty, can we do
drawSierpinskiCarpet(newX(x, y, 0, 2), newY(x, y, 0, 2), order -1)
drawSierpinskiCarpet(newX(x, y, 1, 0), newY(x, y, 1, 0), order -1)
drawSierpinskiCarpet(newX(x, y, 1, 2), newY(x, y, 1, 2), order -1)
better?
drawSierpinskiCarpet(newX(x, y, 2, 0), newY(x, y, 2, 0), order -1)
drawSierpinskiCarpet(newX(x, y, 2, 1), newY(x, y, 2, 1), order -1)
drawSierpinskiCarpet(newX(x, y, 2, 2), newY(x, y, 2, 2), order -1)
Sierpinski Carpet Pseudocode (Take 2)
drawSierpinskiCarpet (x, y, order):
if (order == 0)
drawFilledSquare(x, y, BASE_SIZE)
else
for row = 0 to row = 2:
for col = 0 to col = 2:
if (col != 1 || row != 1):
x_i = newX(x, y, row, col)
y_i = newY(x ,y, row, col)
drawSierpinskiCarpet(x_i, y_i, order - 1)
Iteration + Recursion
● It’s completely reasonable to mix iteration and recursion in the same function.
● Here, we’re firing off eight recursive calls, and the easiest way to do that is with
a double for loop.
● Look for and write down patterns in how to solve the problem as you
increase the number of disks. Try to get to at least 5 disks!
C++ basics
Implementation
User/client
vectors + grids arrays
dynamic memory
stacks + queues
management
sets + maps linked data structures
real-world
Diagnostic algorithms