Remember, when designing algorithms, to first work out a process of what you have to do (then execute it yourself) and fine tune the process. Then, only work on giving the algorithm in pseudo-code or in Scratch.)
When giving ALGORITHMS, DO NOT just give MESSY/COMPLICATED PSEUDO-CODE.
First describe the main ideas behind your algorithm, describe
the main steps and illustrate with simple example if possible.
Think of the poor instructor who has to decode your messy algorithm and TRY to THINK LIKE YOU.
(It is very hard to read and decode algorithms from just MESSY PSEUDO-CODE.)
T4-PP1:
Probs 1 on page 75 (Ch2.3.3) of [SG6]. (not found in [SG3])
What part(s) of the sequential search algorithm of Figure 2.13
would need to be changed if our phone book contained 1 million names
rather than 10,000?
SOLUTION SKETCH:
In the algorithm in Figure 2.13 [SG6], change line 1
(to read in 1000000 names and tel-no, instead of 10000) and
most importantly, the loop in line 3, change from "(i <= 10000)" to "(i <= 1000000)".
A better way is to define a variable, let's say N, that represent the size of the list.
Then, if there are 1000000 names, we just set N <-- 1000000 and
in line 3 (of the loop), change from "(i <= 10000)" to "(i <= N)"
This is much easier for the algorithm Seq-Search given in lecture notes.
We have included the the number of entries as an input parameter m
in the high-level primitive Seq-Search (N, T, m, Name).
So, if there are 1000000 names, we just set m <-- 1000000
before call primitive Seq-Search.
INDEED, this is one of the key advantages of defining high-level primitives.
T4-PP2:
Prob 4 on p.75 (Ch2.3.3) of [SG6]. (was Prob 2 of p.66 of [SG3]) -- SOLUTION SKETCH
Program will "bomb"/"crash" in the line Max-SF <-- A[1].
The program tries to access A[1], which does not exist.
One way to fix it: program should first check if (n>0) and should print error message
and exit the program.
T4-PP3:
Prob 5 on p.75 (Ch2.3.3) of [SG6]. (was Prob 3 of p.66 of [SG3]) -- SOLUTION SKETCH
Program will run normally, if just skip the loop.
T4-PP5:
Prob 16 on p.85 of [SG6] (was p.76 of [SG3]) --- SOLUTION SKETCH
(a) If n ≤ 2, then the test would be true, so the loop
would be executed. In fact, the test would never become
false. Thus, the algorithm would either loop forever, or
generate an error when referring to an invalid A[i] value
(when i is very large and it "overshoots" the valid range of
the array A).
If n > 2, then the test would be false the first time through,
so the loop would be skippped and A[1] would be reported as
the "largest value". [Of course, in this case, the algorithm
would be wrong since it reports the wrong value most of the time.]
(b) The loop will exit when i=n, and so the algorithm would
find the largest of the first n-1 elements. It would not look at
the last element (A[n]).
(c) If n=2, the loop would execute once, comparing A[1] and A[2].
Then the loop would exit on the next pass, return the larger of
the first two values. For any other value of n, the loop would be
skipped, reporting A[1] as the largest value.
Algorithm Swap(X, Y) 1. Temp <-- X; 2. X <-- Y; 2. Y <-- Temp; |
T4-D2: (Simple Cyclic Left Shift Algorithm) -- SOLUTION SKETCH
Several algorithms can be used for cyclic left shift
A <== B <== C <== D <== A (back to A)
|
|
Looking Back at the Solution: The first algorithm is a generalization of the algo for Swap operation, while the second algorithm re-uses the Swap operation. So, you might also say that the first re-uses the method, while the second re-uses the result of the Swap operation. |
Optional FUN: For fun, I add one tricky algorithm for the cyclic left shift that is a bit of a brain twister (esp. the version on the left). I gave an equivalent but simpler version on the right:
|
|
|
|
|
(c) The two processes in algorithm pseudo-code.
Algorithm Repeated-Doubling(n): 1. begin 3. k <-- 1; 2. Count <--0; 4. while (k < n) do 6. k <-- k * 2; (*double it*) 5. Count <-- Count + 1; 7. EndWhile 8. answer <-- Count; 9. end; |
Algorithm Repeated-Halving(n): 1. begin 3. k <-- n; 2. Count <--0; 4. while (k > 0) do 6. k <-- k div 2; (*half it*) 5. Count <-- Count + 1; 7. EndWhile 8. answer <-- Count; 9. end; |
(d)
The general formula for H(n) and D(n) (for all values of n):
H(n) =
⌈lg2(n+1)⌉.
D(n) =
⌈lg2(n)⌉.
For all n (except when n is a power of two), H(n) = D(n).
When n is a power of two (1,2,4,8,16,32,...), H(n) = H(n) + 1.
Verify this with either the formula above or the table above.)
Finally, note for for n = 103, 106, 109,
we have H(n) = D(n) = 10, 20, 30, respectively.
(OPTIONAL: If you *really* want to know how to get H(n), D(n), read Appendix-A, else skip it.)
T4-D3: [Computing Hamming Distance] -- SOLUTION SKETCH
Algorithm Hamming-D(S,R,m); (* Assumes strings S[1..m] and R[1..m] are initialized *) 1. begin 2. Distance <-- 0; 3. k <-- 1; 4. while (k <= m) do 5. if (S[k] not equal to R[k]) then 6. Distance <-- Distance + 1; 7. endif 8. k <-- k + 1; 9. endwhile 10. return Distance 11.end. |
(b): (5 points) [Algorithm for Counting]--- SOLUTION SKETCH
Algorithm Count-Occ (A, n, Num); (* Counts the #times Num appears in array A[1..n] *) begin Count <-- 0; k <-- 1; while (k <= n) do if A[k] = Num then Count <-- Count + 1 endif k <-- k + 1; endwhile return Count end; |
Algorithm Find-Min(D,n); (* Assumes given list is stored in D[1..n] *) 1. begin 2. MinSoFar <-- D[1]; 3. Location <-- 1; k <-- 2; 5. while (k <= n) do 6. if (D[k] < MinSoFar) then 7. MinSoFar <-- D[k]; 8. Location <-- k; 9. endif 10. k <-- k + 1; 11. endwhile 12. return MinSoFar, Location 13.end. |
(b)
Yes, the algorithm will work correctly. When n=1, it correctly report the minimum
as A[1]. (Algorithm does not execute the while-loop, since pre-test condition fails.)
(Note: When you call Find-Min(A,1),
you want to find the min number in the list A[1..1], which means only one number, namely A[1].
It doesn't matter how many item the array A really have.)
T4-Q3: (Reversing an Array) --- SOLUTION SKETCH
Sample: [1 2 3 4 5 6 7 8] --> [8 7 6 5 4 3 2 1].
We discussed two version here:
In the first version uses two pointers left and right.
The left pointer starts from 1, right pointers starts from n.
So the first swap(A[left], A[right])
will first swap A[1] and A[n].
Then the left pointer moves to the right (left <-- left + 1), while
the right pointer moves moves to the left (right <-- right - 1),
So, in the next iteration, swap(A[left], A[right])
will swap A[2] and A[n-1].
In the second version, we only use a left pointer (called k).
since right = (n + 1 - k).
Everything else is the same.
Note that as the left pointer moves right, (n + 1 - k) moves left.
The detailed algorithms are given below:
|
  |
|