###### tags: `learning` `algorithm` `neopolitan`
# 演算法作業02
## ch 2 - 1 Recursive Binary Search
用遞迴的二元搜尋法找出120
```python=
def RecursiveBinarySearch(S, target):
def location(low, high): # python style indexing
if low > high:
return None # target is not in S
else:
mid = math.floor((low + high) / 2)
# ceiling works as well
if S[mid] == target:
return mid
else:
if S[mid] > target: # go to small side
return location(0, mid - 1)
else: # go to large side
return location(mid + 1, high)
# Python uses 0 ~ (n-1) for 1-st ~ n-th
return location(0, len(S) - 1)
```
```python
S = [12, 34, 45, 57, 82, 99, 120, 134]
print(RecursiveBinarySearch(S, 120))
```
## ch 2 - 7 D&C Find The Max
Use the divide-and-conquer approach to write an algorithm that finds the largest item in a list of n items. Analyze your algorithm, and show the results in order notation.
### Ans:
```python=
def mymax(S):
# Conquer the trivial case
if len(S) == 1:
return S[0]
# Divide the combinational case
else:
SS = []
for i in range(len(S) // 2): # === floor(len(S)/2)
# Pick up the winners
if S[2 * i] > S[2 * i + 1]:
SS.append(S[2 * i])
else:
SS.append(S[2 * i + 1])
# Let the lone remainder join the winners
if len(S) % 2:
SS.append(S[-1])
return mymax(SS)
```
Test the answer.
```python=
check_sum = 0
for _ in range(100):
S_len = random.randint(0, 100)
S = [random.randint(0, 10000) for _ in range(S_len)]
if mymax(S) != max(S):
check_sum += 1
print("Fail!")
print(check_sum)
```
Beware of a stack overflow.
```
RecursionError: maximum recursion depth exceeded in comparison
```
## ch 2 - 8 Mergesort / merge sort
Use Mergesort (Algorithms 2.2 and 2.4) to sort the following list. Show the
actions step by step.
> 123, 34, 189, 56, 150, 12, 9, 240
### Ans:
We will use the style of Algorithm 2.4, which saves the extra usage of memory.
**Beware of the pass-by-reference nature of Python.**
**We shall use `U = S[:]` instead of `U = S`.**
```python=
def merge2(low, mid, high):
i = low # for the left/small
j = mid + 1 # for the right/large
k = low # the index for U[]
U = S[:] # the temp list to hold the merged result
# Beware of the pass-by-reference nature of Python
while i <= mid and j <= high:
if S[i] < S[j]:
U[k] = S[i]
i += 1
else:
U[k] = S[j]
j += 1
k += 1
# If one of the U[] or K[] is used up, we don't compare anymore.
# Merge the residual to the sorted part directly
if i > mid: # the left part is used up
U[k:high+1] = S[j:high+1] # Connect the right part onto the tail of U[]
else: # the right part is used up
U[k:high+1] = S[i:mid+1] # Connect the left part onto the tail of U[]
S[low:high+1] = U[low:high+1] # overwirte the yet-merged S[] with the merged U[]
```
```python=
def mergesort2(low, high):
if high > low:
mid = (low + high) // 2 # ===floor( (low + high) // 2 )
mergesort2(low, mid)
mergesort2(mid + 1, high)
merge2(low, mid, high)
```
```python
global S
S = [123, 34, 189, 56, 150, 12, 9, 240]
mergesort2(0,len(S)-1)
```
### step-by-step analysis
Please read https://hackmd.io/s/HJilnclFE
## ch 2 - 19 Quicksort
```cpp=
#include <iostream>
void partition(int S[], int low, int high, int pivotpoint)
{
int i, j, pivotitem, temp;
j = low;
pivotitem = S[low];
for (i = low + 1; i <= high; i++)
{
if (S[i] < pivotitem)
{
j++;
temp = S[i]; S[i] = S[j]; S[j] = temp;
}
}
pivotpoint = j;
temp = S[low]; S[low] = S[pivotpoint]; S[pivotpoint] = temp;
}
void quicksort(int S[], int low, int high)
{
int pivotpoint = low;
if (high > low)
{
partition(S, low, high, pivotpoint);
quicksort(S, low, pivotpoint - 1);
quicksort(S, pivotpoint + 1, high);
}
}
int main()
{
int S[] = {123, 34, 189, 56, 150, 12, 9, 240};
int size = sizeof(S) / sizeof(S[0]);
printf("\nThe size is %d\n\n", size);
int i; for (i = 0; i < size; i++)
printf("%d, ",S[i]);
printf("\n\n");
quicksort(S, 0, size-1);
for (i = 0; i < size; i++)
printf("%d, ",S[i]);
printf("\n");
}
```
## ch 2 - 45
```python=
import random
# Generate a list
S = []
for i in range(4, 100): # set the size of input as N
S.append(random.random())
# Sum the sublists of length-3
S3 = []
initial_index_list = []
for i in range(0,len(S) - 2):
S3.append(S[i] + S[i + 1] + S[i + 2]) # adding for 2N times (for two add symbols)
initial_index_list.append(i)
# find my max
def mymax(S3, index_list): # being called lg(N) times
print(index_list)
if len(index_list) > 1: ## judging for 1 time in each call
new_index_list = []
for i in range(0, len(index_list) - 1, 2):
print(i)
if S3[index_list[i]] > S3[index_list[i+1]]: ## judging for len/2 times in each call
new_index_list.append(index_list[i])
else:
new_index_list.append(index_list[i + 1]) ## judging for 1 time in each call
# collect the unpaired
if len(index_list) % 2:
new_index_list.append(index_list[-1])
return mymax(S3, new_index_list)
else:
return S3[index_list[0]]
# compare with Python's max
print(mymax(S3, initial_index_list) - max(S3))
```
### time complexity
\begin{aligned}
&f(N) = 2N+\lg N (1+\frac{\bf{len}}{2}+1)\\
&\lg N \; \frac{\bf{len}}{2} = 1.5 N
\end{aligned}
So the time complexity fumction is in $\Theta(N)$.
## Appendix B - 8
```python=
def t(n):
if n == 1:
return 1
else:
return t(n-1) + 2 * n - 1
for i in range(1, 11):
print(t(i))
```
The result is `
1,
4,
9,
16,
25,
36,
49,
64,
81,
100`.
Guess the solution is $t(n)=n^2$.
### Induction
* Check $n=1$
Valid.
* Assume valid when $n=k$
$t(k)=k^2$
* Try for the case of $n=k+1$
That is, we want to prove $t(k+1)=(k+1)^2$ from the definition $t(k+1)=t(k)+2k+1$ and the assumption $t(k)=k^2$.
$t(k+1)=k^2+2k+1$
Valid.
Based on Mathematical Induction, we have $t(n)=n^2$ for $n\geq 1$.
## Appendix B - 12
### (a)
\begin{aligned}
&r^2 - 4r + 3 =0 \\
&r=1, 3 \\
&t_n = c_1 + c_2 3^n \\
&t_n = -0.5 + 0.5 \times 3^n
\end{aligned}
### (b)
\begin{aligned}
&(r-1)^4 (r-2) =0 \\
&t_n = c_1 2^n + c_2 1^n + c_3 n 1^n + c_4 n^2 1^n + c_5 n^3 1^n\\
&t_n = 12\times 2^n - 12 - \frac{49}{6}n - \frac{5}{2} n^2 -\frac{1}{3}n^3
\end{aligned}
### \(c\)
\begin{aligned}
&(r-2) (r-3)(r-4) =0 \\
&t_n = c_1 2^n + c_2 3^n + c_3 4^n\\
&t_n = \frac{22}{3}\times 2^n - \frac{23}{2}\times 3^n + \frac{25}{6} 5^n
\end{aligned}
### (d)
\begin{aligned}
t_n = c_1 2^n + c_2 3^n + c_3 7^n + c_4 + c_5 n + c_6 n^2
\end{aligned}
We will use `numpy.linalg.solve(a,b)` to solve the above system of linear equations.
```python=
import numpy as np
# the recursion relationship
def t(n):
if n == 1: return 1
elif n == 0: return 0
else: return (
5*t(n-1) - 6*t(n-2) + n**2-5*n+7**n )
# the function to generate const
def coeff_list(n):
return [2**n,3**n,7**n,1,n,n**2] # return a list
# the coeff to solve C1~C6
coeff_list_list = []
for i in range(0, 6):
print(t(i))
coeff_list_list.append(t(i))
# the const of the six equation
const_list = []
for i in range(0, 6):
print(t(i))
const.append(t(i))
# matrix of coeff
a = np.array(
[ coeff(0),
coeff(1),
coeff(2),
coeff(3),
coeff(4),
coeff(5) ])
# column vector of const
b = np.array(const)
# solve the system of linear equations
c_n = np.linalg.solve(a,b)
print(c_n)
```
The fisrt 6 terms are:
```python
t(0) = 0
t(1) = 1
t(2) = 48
t(3) = 571
t(4) = 4964
t(5) = 38201
```
The coefficients are:
```python
c_1 c_2 c_3 c_4 c_5 c_6
[ 12.8 -14. 2.45 -1.25 1. 0.5 ]
```