0% found this document useful (0 votes)
6 views

ECE 606, Fall 2019, Assignment 5: Zhijie Wang, Student ID Number: 20856733 Zhijie - Wang@uwaterloo - Ca October 8, 2019

Uploaded by

hstrybest
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views

ECE 606, Fall 2019, Assignment 5: Zhijie Wang, Student ID Number: 20856733 Zhijie - Wang@uwaterloo - Ca October 8, 2019

Uploaded by

hstrybest
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 3

ECE 606, Fall 2019, Assignment 5

Zhijie Wang, Student ID number: 20856733

[email protected]
October 8, 2019

1. (a) Proof. Here we use induction to prove this.


Base case: if r − p + 1 = 2, then, q should be r in the return of Partition(A, p, r). And A[p] < A[r],
which is correct.
Step: Our induction is given that r−p+1 = n, the return of QSNew(A, p, r) where A[0, . . . , n − 1], p =
| {z }
n
0, r = n − 1 is sorted as an ascending array. Now if r − p + 1 = n + 1, then, the input array
will be A[0, . . . , n − 1, n]. Here we do a case analysis: (1) A[n] > A[r], (2) A[n] < A[p], and (3)
| {z }
n
A[p] < A[n] < A[r].
(1) If A[n] > A[r], then, A is already sorted. Partition will not change the position of any
elements of the input array because A[r], where r = n is bigger then any other elements of the
array. Hence, the return of Partition is q ← r. Therefore, q − p > r − q, the algorithm will
invoke QSNew(A, r + 1, r), which will terminate because r + 1 > r.
(2) If A[n] < A[p], then, the only thing will happen in Partition is that A[p] will exchange with
A[r], and the return will be q ← p. Since p > q − 1, therefore QSNew(A, p, q − 1) will terminate,
and QSNew(A, q + 1, r) will still only exchange the A[p] and A[r] in this function. Finally, the
function will terminate and then A will be sorted.
(3) If A[p] < A[n] < A[r], then, assume i ∈ A[0, . . . , m] < A[n] < j ∈ A[m + 1, . . . , n − 1]. Hence, the
return of Partition will be q ← m + 1. And from then on, each time QSNew will exchange
the first item with the last one starting from p = m + 1 and return q ← p. Finally the function
will terminate and then A will be sorted.
Therefore, this version of Quick Sort is correct.
(b) Θ(n).
For the worst-case, every time the return of Partition will be b(p + r)/2c, therefore, QSNew
will be invoked n times, and we need a call stack which has a size of n. Therefore, the worst-case
space-efficiency is Θ(n).

2. Let’s denote the equivalence tester as CheckEquivalent(x, y), where x, y are two account numbers, and
it will return T rue if equivalent and F alse else. Assume the number of n cards are stored in an array
A[0, 1, . . . , n − 1] with size n.
HalfEquivalent(A)
1: if HalfCheck(A, 0, n − 1) 6= N one then
2: return T rue
3: else
4: return F alse
HalfCheck(A, p, r)
1: while r − p + 1 > 3 do
2: q ← b(p + r)/2c
3: m1 ←HalfCheck(A, p, q)
4: m2 ←HalfCheck(A, q + 1, r)
5: return CheckValid(A, p, r, m1 , m2 )
6: return CheckValid(A, p, r, p, r)

1
CheckValid(A, p, r, m1 , m2 )
1: if CheckCount(A, p, r, m1 ) then
2: return m1
3: else if CheckCount(A, p, r, m2 ) then
4: return m2
5: else
6: return N one
CheckCount(A, p, r, m)
1: if m = N one then
2: return F alse
3: count ← 0
4: for i from p to r do
5: if CheckEquivalent(A[m], A[i]) then
6: count ← count + 1
7: if count > b(r − p + 1)/2c then
8: return T rue
9: else
10: return F alse
Here we give a brief analysis about the algorithm above. The basic idea is that if there is a number
appears more than half of size’s times in an array, then, this number will still appears more than half of
size’s times in one of arrays which is half of the original array. Therefore, HalfCheck will be invoked
log n times until there are several arrays which has a size of 2 or 3. Then, we invoke CheckValid to
check if there is a number appears more than half of size’s times in each array. And combine the result
of each two arrays, then, check again. Finally, HalfCheck will return a value, if it is not N one, then,
there is such a number appears.
In the worst-case, HalfCheck will be invoked log n times, and each one takes O(n) times to search for
m1 and m2 . Therefore, it needs O(n log n) times of comparisons.
And I think there is another algorithm which only need O(n) comparisons. Here is the pseudo-
code.
HalfEquivalent(A)
1: count ← 1
2: cur ← A[0]
3: for i from 1 to n − 1 do
4: if count = 0 then
5: cur ← A[i]
6: count ← 1
7: else if CheckEquivalent(cur, A[i]) then
8: count ← count + 1
9: else
10: count ← count − 1
11: count ← 0
12: for i from 0 to n − 1 do
13: if CheckEquivalent(cur, A[i]) then
14: count ← count + 1
15: if count > bn/2c then
16: return T rue
17: else
18: return F alse
Now we give a brief analysis on the algorithm above. Assume an account number appears more than n/2
times in n cards, let’s denote the times of appearance as m. Then, m should bigger than the sum of any
other number’s appearances. Every time we select a new cur in Line(4) to Line(6), which means that if
there is no number appears more than half of size’s times before, and we only need to search if there is
a number appears more than half of size’ times after this selection, then say it is cur. (But this number
might not appears more than half of size’s times in the whole array.)
Hence, when the first for-loop ends, if such account number exits, than cur should be this number (Note

2
that here we do not need to copy the value to cur, but only the address, which is similar as a pointer
operation in C++). But actually this number might not exist, so we invoke another for-loop to ensure
that this number’s appearance times is bigger than n/2. In the worst-case we invoke the tester (2n − 1)
times, therefore, our algorithm do comparison only O(n) times.
3. (a) The basic idea of proposed algorithm is to search the minimum numbers of each value. Here we
denote the number of coins of each value is [m0 , m1 , . . . , mn−1 ]. And let’s start from C0 ∈ C =
[C0 , C1 , C2 , . . . Cn−1 ]. And we use the binary search between [0, MinNumCoins(C, a)] for m0 , only
if m0 + MinNumCoins(C[1 :], a − m0 ∗ c0 ) = MinNumCoins(C, a) , then, the m0 is exactly one of
the correct answers. Therefore, for m1 , we only need to search where {C = C[1 : ], a = a − m0 ∗ C0 }.
And in the worst-case, assume the input size is < n = len(C), a = 2s >, therefore the running-time
should be Θ(n log a) = Θ(ns), which is polynomial-time complexity.
Here is the pseudo code about this algorithm. (Length returns the length of list.)
MinCoinsList(C, a)
1: if Length(C) = 1 then
2: return [MinNumCoins(C, a)]
3: C1 ← C.copy()
4: for i from 1 to (Length(C)−1) do
5: result[i] ← BinSearch(C1 , C[i], 0, MinNumCoins(C1 , a), a)
6: a ← a − result[i] ∗ C[i]
7: C1 ← C[j : ]
8: result[Length(C)] ← MinNumCoins(C, a) − Sum(result)
9: return result
BinSearch(C, v, p, r, a)
1: C1 ← C.copy()
2: C1 ← C1 [1 : ]
3: while p <= r do
4: med ← b(p + r)/2c
5: if med + MinNumCoins(C1 , (a − med ∗ v)) = MinNumCoins(C, a) then
6: return med
7: else if med + MinNumCoins(C, (a − med ∗ v)) = MinNumCoins(C, a) then
8: p ← med + 1
9: else
10: r ← med − 1
(b) a5p3b.py

You might also like