Recursive Structures in Programming
Recursive Structures in Programming
● Recursion
○ When a process (function) or structure (data type) is defined in terms of itself
○ Example
■ File system
■ Tree branches
○ Things that are defined in terms of other versions of itself
○ Recursion needs to terminate → base case
○ Made of
■ Base case
● Where recursion ends
■ Recursive step
● Structures
○ Recursive data type
■ Contains itself as an attribute/part of an attribute
● Linked lists vs lists
○
○ Classic list has one object made up of elements
○ Linked lists have node objects that point to other node objects
■ When you want to end list object have it end with none
■ Next is the arrow pointing to next node in list of nodes
● Recursive structures vs functions
○ Base case is in recursive is last function call where we return final function
○ Base case in linked list is last element in list that points to none
○ Once you find node that points to one, you have reached the base case, where
linked list ends
● VS Code
○
● Ending recursion
○ Terminates on a base case
○ Recursive attribute replaced with None type
● In memory
○
● For each magic method call, what is self and (if applicable) what is other?
○ A and b are arguments
○ Self and other are parameters
○
■ Point object must be on left hand side
■ You can call x * 2.0 but not 2.0 * x
○
y
●
● In Python, when you design a class you are able to define what it means when
objects of your class are multiplied, added, and so on to other values.
● In Python, to define how objects of a class behave with respect to arithmetic
operations like addition (+), you need to implement special methods like __add__.
When you write a + b, Python looks for the __add__ method in the class of a. If it's
not found, Python looks in the class of b and its superclasses. The method
signature for __add__ should have two parameters: self and other, where self
refers to the instance on which the method is called, and other refers to the
object being added. It's not required that the second parameter be of type
Fraction, but the __add__ method should be able to handle addition with any
compatible type.
○
● Attributes
○ Variables that belong to each instantiation of the object
○ Syntax
■ <attribute name> : <type>
■ Gluten_free : bool
●
● Constructor
○ Method that defines what happens when new object is created
○ Signature syntax:
■ Def __init__(self, <other parameters>): *Essentially returns self
○ Instantiation:
■ <class name>(<arguments>)
● Methods
○ Functions that belong to an object
○ The first parameter of a method is self and it is given a reference to the
object the method was called on.
○ Calling a method
■ price(my_pizza) → my_pizza.price()
○ Defining a method:
■ Def <method_name>(self, <other parameters>) → <return type>:
■ Def price(self) → float
● Example
○
■ Attributes appear on line 3 and 4.
■ Parameters appear on line 6.
■ Arguments appear on lines 16 and 17.
■ The __init__ constructor is called on lines 16 and 17.
■ If you were to call [Link](), the output would be "Woof!".
■
●
●
●
● Today: Do it in Reverse -
○ Start with recursive Python function
○ From that, get the recursive definition
○ From that, get the sequence representation
○ From that, get the standard definition
●
○ Start with recursive Python function
○ From that, get the recursive definition
■ Base case:
● If n = 0 → mystery(n) = 1
■ Recursive step
● If n > 0 → mystery(n) = 2 x mystery(n-1)
○ From that, get the sequence representation
■
n 0 1 2 3 4 …
F(n) 1 2 4 8 16
■
○ From that, get the standard definition
■ F(n) = 2n
■ Given n, how do I get to F(n)
■ Answer
● Def mystery(n:int) → int:
○ Return 2n
○
LS24 - Intro to Recursion
● Motivation
○ Why recursion?
■ Some programming languages are built entirely around recursive
structures
■ Some functions, sets, or sequences are best represented via recursion
■ Helpful representation for proving things about your functions
● Function in python is called a partial function
●
○ Representing a function as sequence of outputs
● Recursive definition of a function
○ Calling a function within itself, typically with a smaller input.
■ f(n) = f(n/2)
○ Two components:
■ Base case(s)
● Where recursion ends
● Often smallest input(s)
● Prevent infinite loops!
● Ex
○ When n>=0, base case is n=0
■ Recursive Rule
● Definition to handle all inputs that aren’t base case.
● Expresses function in terms of smaller calls to the function.
○ (e.g. expressing f(n) in terms of f(n-1))
○ Finding recursive rule
■
● Looking at how you get from one output to the next
○ Finding base case
■
● Base case will typically be first or first couple outputs
● Base case is where the recursive rule does not apply
○ See bottom right, cannot do this because we are focused on
integers equal to or above 0
● When in doubt, make base case the first element in sequence
○ Writing recursive in python
■
○ Memory diagram
■
● More on recursion
○
■ Recursion rule - n>0 → f(n,b) = f(n-1,b) + 1
■ Base case - n=0 → f(0,b) = b
○
■
○ Insertion Sort Outer loop:
■ Loop over list (everything up to pointer is sorted, everything else is not).
Once you reach the end of the list, you’re done!
■ Inner loop: Swap the object at the pointer backwards until it’s in the
correct position
■
RD01
One of the main models I see in my life is algorithms and cookies in social media and
technology. I would classify these as informal models, as they likely do not rely on true
mathematical calculations or symbolic representations. These models are meant to help the user,
as they cater your media and advertisements to content related to what you may have looked at
or used or purchased before. On one hand, this can be super helpful, as most of the media I
consume is catered to my interests, and I do not have to watch media I am not interested in. On
the other hand, however, this model can make me feel as if I am being watched and my personal
privacy is being violated.
Another model that I have seen in my friends’ lives is the predictions made in sports
betting. The entirety of sports betting is reliant on statistical models of previous games and
player statistics. Without these models, there would be no way of having odds for people to bet
on, and people would not be able to view statistics to base their bets, or future predictions, on.
Thus, these models are very useful for people in the world of sports betting.
In order for an algorithm or model to not cause harm, the algorithm or model should be
fully transparent and clear to those whom it may affect. In the example from the reading, for
example, there is no reason for the ten rows to be blocked off without that being clear and
understood by people at the concert what its purpose is. Not only are unclear models frustrating,
but they are often unnecessary and can avoid potential harms through simple explanation.
To continue, an algorithm or method should be able to be applied across all populations
consistently and fairly. What I mean by this is, no model or algorithm should discriminate or
negatively impact individuals or groups on the basis of their identity. These models are unfair
and will always cause harm so should avoid not being scalable.
Finally, in order to avoid harm, models and algorithms should always avoid any types of
biases that could harm an individual or a group, and they instead should focus on benefiting all
people at all times.
The first paragraph focuses on the idea of limiting opacity, the second focuses on
promoting scalability, and the final paragraph focuses on limiting damages and maximizing
benefits.
●
●
●
●
●
LS19 - Dictionaries
● Dictionaries
○ In lists indexes are keys, values are the values
○ Values can be different types
○ Also called maps, hashmaps, key value stores
● Syntax
○ Data type:
■ Data type: name: dict[<key type>,<value type> ]
■ Ice_cream: dict[str, int]
○ Constructor
■ dict()
● Or
■ ice_cream: dict[str, int] = {"chocolate": 12, "vanilla": 8, "strawberry": 5}
● Can also use single quote
● Dictionary operations
○ Adding elements
■ We use subscription notation
■ <dict name>[<key>] = <value>
■ Ice_cream[“chocolate”] = 12
■ Ice_cream[“mint”] = 3
○ Removing elements
■ Similar to lists, we use pop()
■ <dict name>.pop(<key>)
■ ice_cream.pop(“mint”)
○ Access and modify
■ To access a value, use subscription notation:
● <dict name>[<key>]
● Ice_cream[“vanilla”]
■ To modify, also use subscription notation
● <dict name>[<key>] = new_value
● Ice_cream[“vanilla”] = 9 or ice_cream[“vanilla”] += 1
○ Length of dictionary
■ len(ice_cream)
○ Check if key in dictionary
■ <key> in <dict name>
■ “Mint” in ice_cream
○ Important: cannot have multiple of the same key! Can have duplicates of the same
value
○
○ Using range() in a for … in … loop.
■ names: list[str] = [“Alyssa”, “Janet”, “Vrinda”]
■ Print every element’s index and value:
● 0: Alyssa
● 1: Janet
● 2: Vrinda
○ """Demonstrates range in a for loop."""
○ print(f"{index}:{names[index]}")
●
●
● for…in…loops in memory
○
○
● Writing Code for for in loops
○ pets: list[str] = [“Louie”, “Bo”, “Bear”]
○ Using a for … in … loop, write code to tell each pet they’re a good boy!
○ Challenge: call each elem something other than “elem”
○ Output should be:
■ Good boy, Louie!
■ Good boy, Bo!
■ Good boy, Bear!
○ Answer
■ pets: list[str] = ["Louie", "Bo", "Bear"]
○
■ In the strings, we only add the 6 to a
■ In lists, since b and a are references to same object on heap, we modify
both
● Lists and Functions
○
■ Defining a function on the heap
■ Because we call on course, that is the argument. We then relate it to the
parameter which is xs, which is why course and xs are both id:1
○
■ First step is writing odds list as id:0 in the stack and the lines in occupies
in the heap
■ Then we go down to line 11 and look at global odds which calls us back to
line one, and we create odds_list own section
■ We use values of 2 and 10 as the min and max and line 11 as the RA
■ We give odds an empty list with nothing
■ We then go through the while loop and add to id:1 as we go until done
then write id:1 as return value
■ We then print the list of integers for global odds as a list
● Lists and Functions
○
○ # Return nothing!
○ print(word)
●
●
● Practice Writing Functions
○ Write a different mimic function: you input a string and an index and it returns the
letter at that index. If the index is too high for the string length, return “Index too
high”
■ E.g. mimic_letter(“hello”,0) returns “h”, mimic_letter(“howdy”,2) returns
“w”, mimic_letter(“hi”,3) returns “Index too high”
○ Function name: mimic_letter
■ Parameters: my_words: str, letter_idx: int
■ Return type: str
■ Doc string: """Outputs the character of my_words at index letter_idx"""
○
■ Function name → my_max
■ Parameter list → number1: int, number2: int
■ Return type → int
■ Signature → def my_max(number1: int, number2: int) -> int:
● Call vs signature
○ Call (for calling a function):
■ function_name(<argument list>)
■ my_max(11,3)
○ Signature (for defining a function):
■ Def function_name(<parameter list>) -> <return type>:
■ def my_max(number1: int, number2: int) -> int:
○ Return type should match
○ Function name should match
○ Arguments need to correspond with parameters
●
●
●
○ Enter while loop if condition is true
○ With while loops, once the condition becomes false, finish the operations then
stop
LS12 - counters
● Something you want to keep track or count of
●
●
LS11 - elif
● Combines else and if
○ Allows you to Combine else and if
○ Used between else and if statements
○
○
● Relative Reassignment
○ Reassigning a variable relative to its current value: i = i+ 1
○ Addition re-assignment operator shorthand has the same effect: i += 1
○ Since you will use meaningfully descriptive variable names, this is a big
improvement!
○ total_dollars= total_dollars + next_donation vs total_dollars += next_donation
●
○ 2nd to last line doesn’t matter
○
■ The leading backslash begins an escape sequence
■ The U is an indication that what will follow is an 8-digit hex
representation of a unicode character. Then, to encode 1F920, we must add
three leading 0s for padding because 8 hex digits are expected.
○
● String escape sequences
○ the backslashes in the string "\U0001F920\U0001F40E" are signalling something
special is about to follow the backslash. In this case, what follows is a U which
hints “8 hexidecimal digits encoding a single unicode character” will follow the
\U “escape sequence”
○ Common string sequences
○ How can you use a double quote character in a string surrounded in double
quotes?
■ With the first escape sequence above! For example, the string literal "The
computer said, \"Hello, world.\"" will evaluate to the characters The
computer said, "Hello, world." The \" escape sequence, when evaluated,
results in a quotation character.
○ f-strings “format” strings
■ A key distinction between a regular string and an f-string is that it begins
with the letter f preceeding its quotes.
■
■ Inside of an f-string you can write an expression inside of curly braces and
it will get substituted with the expression’s value when the string literal is
evaluated. Spaces inside of the curly braces are ignored
■
■
LS07 - Memory Diagrams
● Representing what is happening in memory as you step through code
● Will have two boxes - stack and output
○ Everything for now for stack is global
● Example 1
○ Name: str = “Alyssa”
○ Stack is used for name
○ Output is used for the result of the code/things printed
○
● Example 2
○
■ Can put 2 and 4 in quotes because python prints as a string
● CQ00
○
○
● CQ01
○
■ Even though it becomes 2.0, do not print line 5 because we work top to
bottom and we only arrived at 2.0 from line 7
LSO6
● Boolean
○ Something that evaluates to True or False
○ Typically shown with relational operator and/or boolean operator
■ Weather == “rainy”
■ x>=2
● Boolean operators
○ Not, and, or
○ Can be used to express more with booleans
■ It is not rainy: weather != “rain
■ It is not rainy: not (weather!= “rain”)
■ It is rainy and it is cold: (weather == “rain”) and (temperature == “cold”)
● Both statements need to be true for statement to be True
■ It is rainy or it is snowy: (weather == “rain”) or (weather == “snow”)
● Only one has to be true for it to be True
○ Not
■ Not inverts the value of boolean
■
B (normal boolean like temp == Not b
rain
True False
False True
● Weather = “rainy”
○ Weather == rainy
■ True if b
○ Not (weather == rainy)
■ False
○ And
■ Booleans combined with and evaluate to True if and only if both booleans
are True
■
a b a and b
T T T
T F F
F T F
F F F
○ And
■ Booleans combined with or evaluate to True if at least one is True
■
a b a or b
T T F
T F T
F T T
F F F
○ Ordering
■ P
■ E
■ MD
■ A
■ S
■ Not
■ And
■ Or
■
LS05 - Conditionals
● Conditional statement card example
○ If current card < low card, make it the low card
● Conditional statements
○ If <something>:
○ <do something>
○ <rest of program>
● Can also add an else statement
○ If <something>:
○ <do something>
○ else:
○ <do something else>
○ <rest of program>
●
●
○ Line 1 → docstring note to self what program is doing
○ Line 3 → user input function, evaluates user input as a string, user will input a
number but whatever the input is it will be interpreted as a string, string with 5
inside the string
○ Line 4 → print the type of the user input
○ Line 5 → make user number, call it an integer, now changes value into an integer
○ Line 6 → will print out the type of user number, which will be an integer
■ User input is a string, user number will be an int
○ Line 8 → use hashtags to make a comment to yourself, NOT a line of code
○ Line 9 → the beginning of our conditional, if user number is less than 10
○ Line 10 → if it’s less than 10, print the word small
○ Line 11 → else function, if the user number is greater than or equal to 10
■ Basically if line 9 isnt true than do this
○ Line 12 →if the user number is less than or equal to 10, print the word big
○ Line 14 → print back the user input/number given
●
○ Code is same as above except lines 9-12
○ We are trying to see if it is even or odd, so we must use remainder function (%)
○ Line 9 → if the user number has a remainder of 0, it will be even
○ Line 10→ if user number has 0 remainder, print even
○ Line 11 → if the user number has a remainder of 1, it will be odd
○ Line 12→ if user number has 1 remainder, print odd
●
● user_name: str = input("What is your name? ")
LS03 - Expressions
● There are two big ideas behind expressions:
○ Every expression evaluates to a typed value at runtime
■ Every expression evaluates to a specific, concrete type
■ The evaluation of an expression only occurs when the program is running
or when you ask the interactive Python interpreter to evaluate it
○ Anywhere you can write an expression, you can substitute any other expression
of the same type and still have a validly typed program (though it may have
bugs!)
● Literal Expressions
○ When a literal expression is evaluated, it results in an object guided by what was
literally written in code
○ constant values expressed directly in code by providing a concrete, hardcoded
number or string value
● Operator Expressions
○ operators are special symbols, combinations of symbols, or keywords that
designate some type of computation
■ Addition, mult, etc
● Numerical operators
○ Addition, subs, etc
○ Doing a computation with numbers
● Relational operators
○ The evaluation of relational operators always results in a bool value.
○ For example, if you visit a website regarding alcoholic beverages, you will be
asked for your date of birth. The website needs to compare your age with 21 in
order to determine whether to let you into the website, or not. This kind of
comparison tests a relationship, “true or false: 18 is greater than or equal to 21?”
False!
○ True, false, greater than, equal to, etc
● Variable Access
○ A variable access will evaluate to the last value bound to the variable’s name.
○ Basically just writing a line of what x, for example, is equal to then swapping x in
later lines
○
● Constructor Expressions for Type Conversions
○ For types of data that do not have built-in literal syntax, meaning types other than
str, int, and so on, you need a way to construct a new object of that type. Each
type is defined by a class that has a constructor. By convention, the name of the
constructor is the same as the class.
○ Although types such as str and int have literal syntax, they also have constructor
functions. Each of the primitive types’ constructor functions can be used to
convert a value from another type to it. This is best explored through following
along:
■
○ Notice the names, or identifiers, int and str are defined as classes which you can
think of as classifications of a type of data. Each class has a constructor we can
make use of as shown. In the example of int("110"), notice the int constructor
function is able to take in a str and evaluate to an int object. Similarly with the str
constructor, notice we gave it an integer and it evaluated to a str. Often you will
have data in one type and need to convert it to another type for a different
purpose and, in Python, this is how you can.
○ When a constructor call expression evaluates, it always evaluates to the type of
the object it created (and thus it’s name!). So str(123) evaluates to a str typed
object.
● Function Call Expressions
○ Programs tend to be broken down into smaller “subprograms” called functions.
○ A function can often be thought of as a procedure, or a named algorithm, which
you can use to carry out some complex operation more simply.
○
■ In the first examples, the built in round function rounded a float up or
down based on common rounding rules.
■ Next we imported a function named randint from the random package.
■ many functions and types are organized into their own packages to keep
related concepts separate from unrelated concepts. In this case, the
randint function took two inputs in the form of two int values, and when
the randint function evaluated it returned a random int value between
those two numbers.
● Method call expressions
○ Some types of objects have built-in capabilities called methods.
○
○ Each of the expressions you wrote that involved a str, or variable access that
evaluated to a str, followed by a . and then what looks similar to a function call
was a method call expression. As another foreshadowing, the use of a str
variable named msg was included.
● Summary
○ types are fundamentally important to the practice of programming. All of the data
your programs will process, which you can think of as objects in your computer’s
memory, have a specific type. That type is important because it guides the kinds
of expressions you can form and thus the steps of computation you can carry out.
[Link]
Equal? ==
Less than? <
Not equal? !=
○
○ Always result in a bool (True or False)
○ Equals (==) and Not Equal (!=)
■ Can be used for all primitive types we’ve learned so far! (bool, int, float,
str)
○ Every other type
■ Just use on floats and ints
■ (Can technically use on all primitive types)
● Example
○ 220>= int((“1”+”1”+”0”)*2)
■ 220>= int(“11”+ “0”)*2)
■ 220>= int(“110”*2)
■ 220>= int(“110110”)
■ 220>= 110110
● FALSE
○ 7%2=1
○ 8%4=0
○ 7%4=3
○ 2+4/2*2
■ 2+2.0*2
■ 2+4.0
■ 6.0
● Variables
○ Declaration of a variable
■ <name>: <type> = <value>
■ students: int = 300
■ message: str = “Howdy!”
○ Update a variable
■ <name> = <new value>
■ students = 325
■ message = “See ya!”
■
Notes 1/12
● Objects and types
○ Typed unit of data in memory
○ The object’s type ifies it to help the computer know how it should be interpreted
and represented.
● Numerical Built-In Types
○ Integers
■ Int
■ Zero or non-zero digit followed by zero or more integers (e.g. 100 is an int
but 0100 is not)
■ Integers are useful for counting
○ Decimals (Or floats)
■ Float
■ Not the only way to represent decimal numbers, but a very precise way
■ use float for numbers with decimal points
● Textual Built in Type
○ Strings
■ Str
■ A sequence (or string) of characters
■ Can be denoted using “ ”
● Indexing
○ Your way of counting
○ Subscription syntax uses square brackets and allows you to access an item in a
sequence
○ Index numbering starts from 0
■ “12345”[0] → 1
● Docstrings
○ A string written at the top of every file to describe its purpose
○ Denoted with three quotations “““ ”””
● Booleans
○ Bool
○ Evaluates to True or False
● Check an Object’s Type
○ type()
● Change an Object’s Type
○ float()
○ str()
○ int()
Notes 1/12
● Computational Thinking
○ Strategic thought and problem-solving
○ Can help perform a task better, faster, cheaper, etc.
○ Examples:
■ Meal prepping
■ Making your class schedule
■ “Life Hacks
● Algorithms
○ Input is data given to an algorithm
○ An algorithm is a series of steps
○ An algorithm returns some result
○ An algorithm may be influenced by its environment and it may produce
side-effects which influence its environment.
■ Example: planning walk to class
● Input: what the weather is, what the conditions are
● Algorithm: planning out outfit that matches
○ What is an algorithm
■ A set of steps to solve a general problem
■ Finite
■ Can handle a problem of arbitrary size
● Pseudocode
○ Looks like code, but simplified and readable
○ Not meant to run on a computer
○ Helps you outline what your algorithm is going to look like
○ You should be able to expand on your pseudocode to help you write actual code!
○ Pseudocode for cards
■ lowest_card = first card in deck Repeatedly until end of deck: if
current_card < lowest_card: lowest_card = current_card
● Pseudocode
○ simple and readable version of algorithm that resembles code
● Assignment Operator
○ Assigns a variable some value
● Relational Operator
○ Compares two values
● Conditional Statement
○ A statement that only performs an action under certain conditions
● Loop Statement
○ repeat a portion of code a set number of times until the desired process is
complete
● Conditional
○ expressions that evaluate to either true or false
● Function
○ a block of organized, reusable code that is used to perform a single, related action
● Always command S to execute python functions