Labb 2
Labb 2
D0012E
Emil Bank
[email protected]
Joel Willén
[email protected]
Anthony Ågren
[email protected]
Incremental approach:
def incremental(list):
n ← len(list)
x=y=z=∞
for element in list:
if element < x:
z←y
y←x
x ← element
elif element < y:
z←y
y ← element
elif element < z:
z ← element
return [x y z]
Initially the variables x, y and z are set to an infinite value such that any value compared to
these variables must be smaller.
With a for- loop the function iterates through the input once. All except 2 elements in the input
are compared to at most 3 of the variables x, y and z, and at least 1, x.
Index 0 in the input will always be smaller than x, and index 1 will always be smaller than y,
since x and y represent an infinite value to begin with. Thus the maximum number of
comparisons for n = 3 is 6.
For any arbitrary n larger than 3, the maximal number of comparisons happens when no
element past index 1 is smaller than y, such that all elements except 2 are compared three
times. The first two elements, as mentioned above, will only compare once and twice
respectively. Expressed as a function of n we write:
The function returns a list of the variables x, y and z at index 0, 1 and 2 respectively. And for any
input of size larger than or equal to 3, x, y and z must represent the three smallest elements in
the input such that x < y < z is the output.
BASE CASE, n = 3
Base case is the same exact operation as the Incremental approach, with the only exception
that the input is always 3.
Hence the number of comparisons in the base case must, in the worst case, always be 6.
𝐶(𝑛) = 6 (3)
𝑇(𝑛) = Θ(3) (4)
RECURSION
Assume input of size n distinct values, such that:
𝑘−1
𝑛 = 3· 2 and 𝑘 ≥ 1 (5)
Then we can utilize that n is 3 times 2 raised to the integer k - 1 such that:
𝑘−1 𝑛
𝑛 = 3· 2 ⇔ 3
𝑚𝑜𝑑 2 = 0, with the constraint that 𝑘 ≥ 2 (6)
Thus we divide n with 2, and each half is the argument for a separate recursion to ultimately end
up with n = 3, which then will hold true for our base case. The number of recursion calls and
sublists created to ultimately end up in the base case will equal:
𝑛 𝑘−1
3
=2 (7)
And since the number of comparisons made in base case for the worst case is equal to 6 (eq.
3), the maximum number of comparisons in base case for any input of size n is:
𝑛
6 · 3
= 2𝑛 (8)
Minvalues is a tuple of two sublists, such that minvalues = ( [𝑥0, 𝑦0, 𝑧0], [𝑥1, 𝑦1, 𝑧1] ).
For every factor of 2 n increases, the need for recursion increases by 2. In other words, each
time the statement for base case is not valid, we must split the list, as stated in equation 6. Thus
the number of instances of minvalues tuples will be equal to:
𝑛−3
3
(9)
Each minvalues tuple will then be fed through a while-loop that will execute while ℎ < 3.
i, j and h, three variables used in the while-loop will initiate as 0 respectively. Each iteration h will
be increased by 1, no matter if the if- statement is executed inside of the loop. This way the total
number of iterations per minvalues tuple is always 3.
Either i or j will increase by one each iteration depending on if the if- statement is true.
In the if- statement minvalues[ 0 ][ i ] represents the sorted sublist at index 0 in the tuple,
[𝑥0, 𝑦0, 𝑧0], and i is a variable for the index inside of index 0. minvalues[ 1 ][ j ] is the sublist at
index 1 in the tuple, [𝑥1, 𝑦1, 𝑧1], and j is the variable representing the index inside of index 1.
Since both sublists in the tuple at this point must have been fed through the base case, we
know that index 0 and index 1 must be in the format x < y < z.
To find the three smallest elements of the combined list in the tuple, the comparison starts at
[0][0] and [1][0] respectively, and increases only for the index containing the smallest element in
the comparison for that iteration. When the loop has been executed three iterations the returnlist
thus must have been appended the three smallest elements in the tuple. The loop terminates
and the function returns the returnlist.
Depending on which depth in the recursion the while- loop was executed, the returnlist will
either be fed into a more shallow minvalues tuple, or it will be the list containing the three
smallest elements of the input.
Since for every minvalues tuple there must always be 3 comparisons, the number of
comparisons for all minvalues tuples are 3 times the number of minvalues tuples (eq. 9):
𝑛−3
3 · 3
= 𝑛 −3 (10)
To calculate the maximum number of comparisons for any input of size n we add the number of
comparisons for the base cases and the number of comparisons for minvalues (eq. 8 + 10):
Class Sum:
def(__init__(self, value):
self.total ← value
self.max_sum ← value
self.max_trailing_sum ← value
self.max_leading_sum ← value
max_subarray_info ← Sum(0)
return max_subarray_info
The approach:
Initially, the algorithm defines a Sum class with instance variables ‘total’, ‘max_sum’,
‘max_leading_sum’ and ‘max_trailing_sum’. These attributes represent the total sum of a
consecutive subarray, the maximum consecutive subarray sum, the maximum leading sum of a
subarray on the left, and the maximum trailing sum of a subarray on the right. These attributes
are initialized with a given value.
The algorithm then relies on the function max_sum, which takes the three parameters ‘lst’,
‘lower’ and ‘upper’, which represents a list, and a lower and an upper index. The main purpose
of the function is to apply a divide-and-conquer approach to the specified array and within
specified range.
The algorithm first checks for a base case, where the lower and upper indices are equal,
meaning there’s only 1 element in the specified subarray. If that is the case, it returns a ‘Sum’
object with the value of that element.
Next, the algorithm calculates the middle index of the specified subarray using the lower and
upper bounds to divide the problem into two smaller sub-problems.
Afterwards, the algorithm performs recursive calls to ‘max_sum’ for the left and right halves of
the subarray, using the range of ‘lower’ to ‘mid’ for the left half and ‘mid + 1’ to ‘upper’ for the
right half.
Following that, a ‘Sum’ object, ‘max_subarray_info’, is initialized to hold information for the
current subarray. The ‘total’ attributes of the the left and right subarrays are then added together
to define the ‘total’ of the ‘max_subarray_info’ object.
The algorithm then computes the maximum leading sum, maximum trailing sum and maximum
subarray sum. This demands updates and comparisons using either of two alternatives (built in
max function or an extensive amount of if-then-else statements). The ambition is to determine
and keep track of the maximum leading sum, maximum trailing sum and maximum subarray
sum of the current subarray.
Finally, the algorithm returns the ‘max_subarray_info’ object, which now contains updated
information about the current specified array. The recursive structure of the algorithm, combined
with thorough comparisons, allows it to quickly identify the solution to the max subarray
problem, which is retrieved through the ‘max_sum’ attribute of the object.
= Θ(𝑛) (15)