Sequences
Question 0
Fill out what python would display at each step if applicable.
Note: (keep in mind list slicing creates a brand new list, does not modify existing list)
i.
1 | 1, 2, 3, 4, 5] lst = [ |
ii. Hint: You can also specify the increment step-size for slicing. The notation is lst[start:end:step].
Remember that a negative step size changes the default start and end.
1 | 1:4:2] lst[ |
Question 1
Draw the environment diagram that results from running the code below
1 | def reverse(lst): |
EXTRA: Question 2
Write combine_skipper
, which takes in a function f
and list lst
and outputs a list. When this function takes in a list lst
, it looks at the list in chunks of four and applies f
to the first two elements in every set of four elements and replaces the first element with the output of the function f applied to the two elements as the first value and the index of the second item of the original two elements as the second value of the new two elements. f
takes in a list and outputs a value. [Assume the length of lst
will always be divisible by four]
1 | def combine_skipper(f, lst): |
Mutability
Question 0
a. Name two data types that are mutable. What does it mean to be mutable?
Dictionaries, lists
b. Name two data types that are not mutable.
Tuples, functions, int, float
Question 1
a. Will the following code error? Why?
1 | 1 a = |
No, a and b are immutable type
b. Will the following code error? Why?
1 | 1] a = [ |
Yes, a and b are mutable types
Question 2
a. Fill in the output and draw a box-and-pointer diagram for the following code. If an error occurs, write “Error”, but include all output displayed before the error.
1 | 1, [2, 3], 4] a = [ |
b. Fill in the output and draw a box-and-pointer diagram for the following code. If an error occurs, write “Error”, but include all output displayed before the error.
1 | 5, 6, 7] lst = [ |
Data Abstraction
Question 1
a. Why are Abstract Data Types useful?
- More readable code.
- Constructors and selectors have human-readable names.
- Makes collaboration easier.
- Other programmers don’t have to worry about implementation details.
- Prevents error propagation.
- Fix errors in a single function rather than all over your program.
b. What are the two types of functions necessary to make an Abstract Data Type? Describe what they do. - Constructors make the ADT.
- Selectors take instances of the ADT and output relevant information stored in it.
c. What is a Data Abstraction Violation?
Put simply, a Data Abstraction Violation is when you bypass the constructors and selectors for an ADT, and directly use how it’s implemented in the rest of your code, thus assuming that its implementation will not change.
d. Why is it a terrible sin to commit a Data Abstraction Violation?
We cannot assume we know how the ADT is constructed except by using constructors and likewise, we cannot assume we know how to access details of our ADT except through selectors. The details are supposed to be abstracted away by the constructors and selectors. If we bypass the constructors and selectors and access the details directly, any small change to the implementation of our ADT could break our entire program.
Question 2
In lecture, we discussed the rational data type, which represents fractions with the following methods:
• rational(n, d) - constructs a rational number with numerator n, denominator d
• numer(x) - returns the numerator of rational number x
• denom(x) - returns the denominator of rational number x
We also presented the following methods that perform operations with rational numbers:
• add_rationals(x, y)
• mul_rationals(x, y)
• rationals_are_equal(x, y)
You’ll soon see that we can do a lot with just these simple methods in the exercises below.
a. Write a function that returns the given rational number x raised to positive power e.
1 | from math import pow |
b. Implement the following rational number methods.
1 | def inverse_rational(x): |
c. The irrational number e ≈ 2.718 can be generated from an infinite series. Let’s try calculating it using our rational number data type! The mathematical formula is as follows:
Write a function approx_e that returns a rational number approximation of e to iter amount of iterations. We’ve provided a factorial function.
1 | def factorial(n): |
Question 3
Assume that rational
, numer
, and denom
, run without error and work like the ADT defined in Question 2. Can you identify where the abstraction barrier is broken? Come up with a scenario where this code runs without error and a scenario where this code would stop working.
1 | def rational(num, den): # Returns a rational number ADT |
The abstraction barrier is broken inside simplify(f1) when calling gcd(f1[0], f1[1]). This assumes rational returns a type that can be indexed through. i.e. This would work if rational returned a list. However, this would not work if rational returned a dictionary.
The correct implementation of simplify would be
1 | def simplify(f1): |
Trees
Question 0
a. Fill in this implementation of a tree:
1 | def tree(label, branches = []): |
b. A min-heap is a tree with the special property that every node’s value is less than or equal to the values of all of its children. For example, the following tree is a min-heap:
However, the following tree is not a min-heap because the node with value 3 has a value greater than one of its children:
Write a function is_min_heap
that takes a tree and returns True if the tree is a min-heap and False otherwise.
1 | def is_min_heap(t): |
c. Write a function largest_product_path
that finds the largest product path possible. A product path is defined as the product of all nodes between the root and a leaf. The function takes a tree as its parameter. Assume all nodes have a nonnegative value.
For example, calling largest_product_path
on the above tree would return 42, since 3 * 7 * 2 is the largest product path.
1 | def largest_product_path(tree): |
Challenge Question (Optional)
Come back after finishing everything!
The level-order traversal of a tree is defined as visiting the nodes in each level of a tree before moving onto the nodes in the next level. For example, the level order of the following tree is,
Level-order: 3 7 8 4
a. Write a function print_level_sorted
that takes in a tree as the parameter and returns a list of the values of the nodes in level order.
1 | # Iterative implementation |