Lec 1
Lec 1
Algorithms
An algorithm is a computational procedure that takes values as input and produces values
as output. In the process it solves a computational problem.
An instance of a problem is any specific input.
We will specify our algorithms in pseudo-code using standard programming constructs such
as for-rof, if-fi, while loop, repeat loop and function and procedure calls. We will not
confine ourselves to any particular programming language; using English phrases is fine as
long as they describe the algorithm unambiguously. (No type declarations, etc. necessary
unless needed for clarity.)
Your textbook uses indentation to demark the scope of while loops, etc. For your homeworks
it is better to use begin-end or the constructs listed above, especially if your pseudo-code
runs across more than one page.
This is a theoretical class where we will study
• algorithms for important combinatorial problems,
• methods of analyzing the performance of algorithms. Our primary measure for the
quality of an algorithm is its worst-case running time. We will sometimes study ex-
pected running time or ‘amortized’ running time, and sometime we will look at other
resources such as space (i.e., memory) usage.
Any algorithm you present in your homeworks, tests or exam must be accompanied by a
proof of correctness. Correctness may proved using either equations or unambiguous English
sentences, depending on which is more convenient.
Sorting
Given an array A[1..n] of elements from a totally ordered set, the output of the sorting
problem is the same array A with its elements rearranged in sorted order, i.e., after execution
of a sorting algorithm, the array A contains the same set of elements as in the input array,
but in the output array A[i] ≤ A[i + 1] for 1 ≤ i ≤ n − 1.
There are many beautiful and interesting algorithms known for the sorting problem. We will
start by looking at Merge-sort. (Note: In general, given an array B[s..t], where s and t are
integers, if s > t, then we assume that B is the empty array.)
Merge-Sort(A, p, r)
Input. A is an array A[1..n] of elements from a totally ordered set; p and r are integers
with 1 ≤ p ≤ r ≤ n.
Output. The elements in sub-array A[p..r] are rearranged in sorted order; the elements in
array A outside of subarray A[p..r] are unchanged. (So initial call is to A[1..n].)
if p < r then
q := b (p+r)
2
c
Merge-Sort(A, p, q)
Merge-Sort(A, q + 1, r)
Merge(A, p, q, r)
fi
Merge(A, p, q, r)
Input. A is an array A[1..n] of elements from a totally ordered set; p, q, r are integers with
1 ≤ p ≤ q < r ≤ n; subarrays A[p..q] and A[q + 1..r] are both sorted.
Output. The elements in sub-array A[p..r] are rearranged in sorted order; the elements in
array A outside of subarray A[p..r] are unchanged.
• Assuming Merge runs in time linear in the size of its input, analyze the running time
of Merge-Sort.
Page 2
Correctness of Merge-Sort
For simplicity, let us assume that n = 2k , for some k ≥ 0. Then, inspecting the pseudocode,
we see that if k > 0 (i.e., if n ≥ 2), then a call to Merge-Sort(A, 1, n) makes a recursive call
to Merge-Sort(A, 1, n/2) and then a recursive all to Merge-Sort(A, n2 + 1, n), followed
by a call to Merge(A, 1, n/2, n).
Let us use T (n) to denote the (worst-case) running time of Merge-Sort on any input
array of n elements, for any n ≥ 1. Then, each of the two recursive calls to Merge-Sort
on arrays of size n/2 will take worst-case time T (n/2). We have already assumed that the
time taken by Merge(A, 1, n/2, n) is proportional to n, i.e., it is d · n for some constant d
that is independent of n. So, we can write out the following expression for the worst-case
running time of Merge-Sort:
(
c if n = 1
T (n) =
2 · T (n/2) + d · n if n > 1
Page 3
Merge
Merge(A, p, q, r)
Input. A is an array A[1..n] of elements from a totally ordered set; p, q, r are integers with
1 ≤ p ≤ q < r ≤ n; subarrays A[p..q] and A[q + 1..r] are both sorted.
Output. The elements in sub-arry A[p..r] are rearranged in sorted order; the elements in
array A outside of subarray A[p..r] are unchanged.
1. Let n1 = q − p + 1; n2 = r − q.
Copy A[p..q] into array L[1..n1 ];
Copy A[q + 1..r] into array R[1..n2 ]
set i = 1; j = 1
2. for k := p to r do
if L[i] ≤ R[j] then
A[k] := L[i]; i := i + 1 else
A[k] := R[j]; j := j + 1
fi
rof
Correctness of Merge.
• Step 1 copies subarray A[p..q] into L[1..n1 ] and A[q + 1..n2 ] into R[1..n2 ].
Page 4