Skip to content

Week-3 (Matrix Multiplication/Quick Sort)

CE100 Algorithms and Programming II

Week-3 (Matrix Multiplication/ Quick Sort)

Spring Semester, 2021-2022

Download DOC-PDF, DOC-DOCX, SLIDE, PPTX


Matrix Multiplication / Quick Sort

Outline (1)

  • Matrix Multiplication

  • Traditional

  • Recursive

  • Strassen


Outline (2)

  • Quicksort

  • Hoare Partitioning

  • Lomuto Partitioning

  • Recursive Sorting


Outline (3)

  • Quicksort Analysis

  • Randomized Quicksort

  • Randomized Selection

    • Recursive

    • Medians


Matrix Multiplication (1)

  • Input: \(A=[a_{ij}],B=[b_{ij}]\)
  • Output: \(C=[c_{ij}]=A \cdot B\) \(\Longrightarrow i,j=1,2,3, \dots, n\)
\[ \begin{bmatrix} c_{11} & c_{12} & \dots & c_{1n} \\ c_{21} & c_{22} & \dots & c_{2n} \\ \vdots & \vdots & \vdots & \ddots \\ c_{n1} & c_{n2} & \dots & c_{nn} \\ \end{bmatrix} = \begin{bmatrix} a_{11} & a_{12} & \dots & a_{1n} \\ a_{21} & a_{22} & \dots & a_{2n} \\ \vdots & \vdots & \vdots & \ddots \\ a_{n1} & a_{n2} & \dots & a_{nn} \\ \end{bmatrix} \cdot \begin{bmatrix} b_{11} & b_{12} & \dots & b_{1n} \\ b_{21} & b_{22} & \dots & b_{2n} \\ \vdots & \vdots & \vdots & \ddots \\ b_{n1} & a_{n2} & \dots & b_{nn} \\ \end{bmatrix} \]

Matrix Multiplication (2)

alt:"alt" height:450px center

  • \(c_{ij}=\sum \limits_{1\leq k \leq n}^{}a_{ik}.b_{kj}\)

Matrix Multiplication: Standard Algorithm

Running Time: \(\Theta(n^3)\)

for i=1 to n do
    for j=1 to n do
        C[i,j] = 0
        for k=1 to n do
            C[i,j] = C[i,j] + A[i,k] + B[k,j]
        endfor
    endfor
endfor

Matrix Multiplication: Divide & Conquer (1)

IDEA: Divide the \(nxn\) matrix into \(2x2\) matrix of \((n/2)x(n/2)\) submatrices.

alt:"alt" height:450px center


Matrix Multiplication: Divide & Conquer (2)

\[ \begin{bmatrix} c_{11} & c_{12} \\ c_{21} & c_{22} \end{bmatrix} = \begin{bmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{bmatrix} \cdot \begin{bmatrix} b_{11} & b_{12} \\ b_{21} & b_{22} \end{bmatrix} \]
\[ \text{8 mults and 4 adds of (n/2)*(n/2) submatrices}= \begin{cases} c_{11}=a_{11}b_{11}+a_{12}b_{21} \\ c_{21}=a_{21}b_{11}+a_{22}b_{21} \\ c_{12}=a_{11}b_{12}+a_{12}b_{22} \\ c_{22}=a_{21}b_{12}+a_{22}b_{22} \end{cases} \]

Matrix Multiplication: Divide & Conquer (3)

MATRIX-MULTIPLY(A, B)
    // Assuming that both A and B are nxn matrices
    if n == 1 then 
        return A * B
    else  
        //partition A, B, and C as shown before
        C[1,1] = MATRIX-MULTIPLY (A[1,1], B[1,1]) + 
                 MATRIX-MULTIPLY (A[1,2], B[2,1]); 

        C[1,2] = MATRIX-MULTIPLY (A[1,1], B[1,2]) + 
                MATRIX-MULTIPLY (A[1,2], B[2,2]); 

        C[2,1] = MATRIX-MULTIPLY (A[2,1], B[1,1]) + 
        MATRIX-MULTIPLY (A[2,2], B[2,1]);

        C[2,2] = MATRIX-MULTIPLY (A[2,1], B[1,2]) + 
        MATRIX-MULTIPLY (A[2,2], B[2,2]);
    endif      

    return C

Matrix Multiplication: Divide & Conquer Analysis

\(T(n) = 8T(n/2) + \Theta(n^2)\)

  • \(8\) recursive calls \(\Longrightarrow 8T(\cdots)\)
  • each problem has size \(n/2\) \(\Longrightarrow \cdots T(n/2)\)
  • Submatrix addition \(\Longrightarrow \Theta(n^2)\)

Matrix Multiplication: Solving the Recurrence

  • \(T(n) = 8T(n/2) + \Theta(n^2)\)

  • \(a=8\), \(b=2\)

  • \(f(n)=\Theta(n^2)\)
  • \(n^{log_b^a}=n^3\)

  • Case 1: \(\frac{n^{log_b^a}}{f(n)}=\Omega(n^{\varepsilon}) \Longrightarrow T(n)=\Theta(n^{log_b^a})\)

Similar with ordinary (iterative) algorithm.


Matrix Multiplication: Strassen’s Idea (1)

Compute \(c_{11},c_{12},c_{21},c_{22}\) using \(7\) recursive multiplications.

In normal case we need \(8\) as below.

\[ \begin{bmatrix} c_{11} & c_{12} \\ c_{21} & c_{22} \end{bmatrix} = \begin{bmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{bmatrix} \cdot \begin{bmatrix} b_{11} & b_{12} \\ b_{21} & b_{22} \end{bmatrix} \]
\[ \text{8 mults and 4 adds of (n/2)*(n/2) submatrices}= \begin{cases} c_{11}=a_{11}b_{11}+a_{12}b_{21} \\ c_{21}=a_{21}b_{11}+a_{22}b_{21} \\ c_{12}=a_{11}b_{12}+a_{12}b_{22} \\ c_{22}=a_{21}b_{12}+a_{22}b_{22} \end{cases} \]

Matrix Multiplication: Strassen’s Idea (2)

  • Reminder:
  • Each submatrix is of size \((n/2)*(n/2)\)
  • Each add/sub operation takes \(\Theta(n^2)\) time
  • Compute \(P1 \dots P7\) using \(7\) recursive calls to matrix-multiply
\[ \begin{align*} P_1 & = a_{11} * (b_{12} - b_{22} ) \\ P_2 & = (a_{11} + a_{12} ) * b_{22} \\ P_3 & = (a_{21} + a_{22} ) * b_{11} \\ P_4 & = a_{22} * (b_{21} - b_{11} ) \\ P_5 & = (a_{11} + a_{22} ) * (b_{11} + b_{22} ) \\ P_6 & = (a_{12} - a_{22} ) * (b_{21} + b_{22} ) \\ P_7 & = ( a_{11} - a_{21} ) * (b_{11} + b_{12} ) \end{align*} \]

Matrix Multiplication: Strassen’s Idea (3)

\[ \begin{align*} P_1 &= a_{11} * (b_{12} - b_{22} ) \\ P_2 &= (a_{11} + a_{12} ) * b_{22} \\ P_3 &= (a_{21} + a_{22} ) * b_{11} \\ P_4 &= a_{22} * (b_{21} - b_{11} ) \\ P_5 &= (a_{11} + a_{22} ) * (b_{11} + b_{22} ) \\ P_6 &= (a_{12} - a_{22} ) * (b_{21} + b_{22} ) \\ P_7 &= ( a_{11} - a_{21} ) * (b_{11} + b_{12} ) \end{align*} \]
  • How to compute \(c_{ij}\) using \(P1 \dots P7\) ?
\[ \begin{align*} c_{11} & = P_5 + P_4 – P_2 + P_6 \\ c_{12} & = P_1 + P_2 \\ c_{21} & = P_3 + P_4 \\ c_{22} & = P_5 + P_1 – P_3 – P_7 \end{align*} \]

Matrix Multiplication: Strassen’s Idea (4)

  • \(7\) recursive multiply calls
  • \(18\) add/sub operations

Matrix Multiplication: Strassen’s Idea (5)

e.g. Show that \(c_{12} = P_1+P_2\) :

\[ \begin{align*} c_{12} & = P_1 + P_2 \\ &= a_{11}(b_{12}–b_{22})+(a_{11}+a_{12})b_{22} \\ &= a_{11}b_{12}-a_{11}b_{22}+a_{11}b_{22}+a_{12}b_{22} \\ &= a_{11}b_{12}+a_{12}b_{22} \end{align*} \]

Strassen’s Algorithm

  • Divide: Partition \(A\) and \(B\) into \((n/2)*(n/2)\) submatrices. Form terms to be multiplied using \(+\) and \(-\).

  • Conquer: Perform \(7\) multiplications of \((n/2)*(n/2)\) submatrices recursively.

  • Combine: Form \(C\) using \(+\) and \(–\) on \((n/2)*(n/2)\)submatrices.

Recurrence: \(T(n) = 7T(n/2) + \Theta(n^2)\)


Strassen’s Algorithm: Solving the Recurrence (1)

  • \(T(n) = 7T(n/2) + \Theta(n^2)\)

  • \(a=7\), \(b=2\)

  • \(f(n)=\Theta(n^2)\)
  • \(n^{log_b^a}=n^{lg7}\)

  • Case 1: \(\frac{n^{log_b^a}}{f(n)}=\Omega(n^{\varepsilon}) \Longrightarrow T(n)=\Theta(n^{log_b^a})\)

\(T(n)=\Theta(n^{log_2^7})\)

\(2^3 = 8, 2^2=4\) so \(\Longrightarrow log_2^7 \approx 2.81\)

or use https://www.omnicalculator.com/math/log


Strassen’s Algorithm: Solving the Recurrence (2)

  • The number \(2.81\) may not seem much smaller than \(3\)

  • But, it is significant because the difference is in the exponent.

  • Strassen’s algorithm beats the ordinary algorithm on today’s machines for \(n \geq 30\) or so.

  • Best to date: \(\Theta(n^{2.376 \dots})\) (of theoretical interest only)


Matrix Multiplication Solution Faster Than Strassen's Algorithm


Matrix Multiplication Solution Faster Than Strassen's Algorithm

For example, if the traditional algorithm taught in school multiplies a 4x5 by 5x5 matrix using 100 multiplications, and this number was reduced to 80 with human ingenuity, AlphaTensor has found algorithms that do the same operation using just 76 multiplications.


Matrix Multiplication Solution Faster Than Strassen's Algorithm

![center h:450px]


Standard Multiplication

center h:400px


Standard and Strassen Comparison

bg right h:650px


Improved Solution

bg right  h:660px


How it's done

"Single-player game played by AlphaTensor, where the goal is to find a correct matrix multiplication algorithm. The state of the game is a cubic array of numbers (shown as grey for 0, blue for 1, and green for -1), representing the remaining work to be done."

center h:350px


Maximum Subarray Problem

Input: An array of values

Output: The contiguous subarray that has the largest sum of elements

  • Input array: \([13][-3][-25][20][-3][-16][-23]\overbrace{[18][20][-7][12]}^{\textrm{max. contiguous subarray}}[-22][-4][7]\)

Maximum Subarray Problem: Divide & Conquer (1)

  • Basic idea:
  • Divide the input array into 2 from the middle
  • Pick the best solution among the following:
    • The max subarray of the left half
    • The max subarray of the right half
    • The max subarray crossing the mid-point

Maximum Subarray Problem: Divide & Conquer (2)

alt:"alt" height:450px center


Maximum Subarray Problem: Divide & Conquer (3)

  • Divide: Trivial (divide the array from the middle)

  • Conquer: Recursively compute the max subarrays of the left and right halves

  • Combine: Compute the max-subarray crossing the \(mid-point\)

  • (can be done in \(\Theta(n)\) time).

  • Return the max among the following:
    • the max subarray of the \(\text{left-subarray}\)
    • the max subarray of the \(\text{rightsubarray}\)
    • the max subarray crossing the \(\text{mid-point}\)

TODO : detailed solution in textbook...


Conclusion : Divide & Conquer

  • Divide and conquer is just one of several powerful techniques for algorithm design.
  • Divide-and-conquer algorithms can be analyzed using recurrences and the master method (so practice this math).
  • Can lead to more efficient algorithms

Quicksort (1)

  • One of the most-used algorithms in practice
  • Proposed by C.A.R. Hoare in 1962.
  • Divide-and-conquer algorithm
  • In-place algorithm
  • The additional space needed is O(1)
  • The sorted array is returned in the input array
  • Reminder: Insertion-sort is also an in-place algorithm, but Merge-Sort is not in-place.
  • Very practical

Quicksort (2)

  • Divide: Partition the array into 2 subarrays such that elements in the lower part \(\leq\) elements in the higher part
  • Conquer: Recursively sort 2 subarrays
  • Combine: Trivial (because in-place)

Key: Linear-time \((\Theta(n))\) partitioning algorithm

alt:"alt" height:200px center


Divide: Partition the array around a pivot element

  • Choose a pivot element \(x\)

  • Rearrange the array such that:

  • Left subarray: All elements \(\leq x\)

  • Right subarray: All elements \(\geq x\)

alt:"alt" height:350px center


Conquer: Recursively Sort the Subarrays

Note: Everything in the left subarray ≤ everything in the right subarray

alt:"alt" height:350px center

Note: Combine is trivial after conquer. Array already sorted.


Two partitioning algorithms

  • Hoare’s algorithm: Partitions around the first element of subarray
  • \((pivot = x = A[p])\)

alt:"alt" height:100px center

  • Lomuto’s algorithm: Partitions around the last element of subarray
  • \((pivot = x = A[r])\)

alt:"alt" height:100px center


Hoare’s Partitioning Algorithm (1)

  • Choose a pivot element: \(pivot = x = A[p]\)

alt:"alt" height:100px center

  • Grow two regions:
  • from left to right: \(A[p \dots i]\)
  • from right to left: \(A[j \dots r]\)
    • such that:
  • every element in \(A[p \dots i] \leq\) pivot
  • every element in \(A[p \dots i] \geq\) pivot

Hoare’s Partitioning Algorithm (2)

alt:"alt" height:550px center


Hoare’s Partitioning Algorithm (3)

  • Elements are exchanged when
  • \(A[i]\) is too large to belong to the left region
  • \(A[j]\) is too small to belong to the right region
    • assuming that the inequality is strict
  • The two regions \(A[p \dots i]\) and \(A[j \dots r]\) grow until \(A[i] \geq pivot \geq A[j]\)
  H-PARTITION(A, p, r)
        pivot = A[p]
          i = p - 1
          j = r - 1
          while true do
            repeat j = j - 1 until A[j] <= pivot
            repeat i = i - 1 until A[i] <= pivot
          if i < j then 
            exchange A[i] with A[j]
          else 
            return j

Hoare’s Partitioning Algorithm Example (Step-1)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm Example (Step-2)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm Example (Step-3)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm Example (Step-4)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm Example (Step-5)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm Example (Step-6)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm Example (Step-7)

alt:"alt" height:550px center


Hoare’s Partitioning Algorithm Example (Step-8)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm Example (Step-9)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm Example (Step-10)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm Example (Step-11)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm Example (Step-12)

alt:"alt" height:500px center


Hoare’s Partitioning Algorithm - Notes

  • Elements are exchanged when
  • \(A[i]\) is too large to belong to the left region
  • \(A[j]\) is too small to belong to the right region
    • assuming that the inequality is strict
  • The two regions \(A[p \dots i]\) and \(A[j \dots r]\) grow until \(A[i] \geq pivot \geq A[j]\)
  • The asymptotic runtime of Hoare’s partitioning algorithm \(\Theta(n)\)
  H-PARTITION(A, p, r)
        pivot = A[p]
          i = p - 1
          j = r - 1
          while true do
            repeat j = j - 1 until A[j] <= pivot
            repeat i = i - 1 until A[i] <= pivot
          if i < j then exchange A[i] with A[j]
          else return j

Quicksort with Hoare’s Partitioning Algorithm

QUICKSORT (A, p, r)
  if p < r then
    q = H-PARTITION(A, p, r)
    QUICKSORT(A, p, q)
    QUICKSORT(A, q + 1, r)
  endif

Initial invocation: QUICKSORT(A,1,n)

alt:"alt" height:150px center


Hoare’s Partitioning Algorithm: Pivot Selection

  • if we select pivot to be \(A[r]\) instead of \(A[p]\) in H-PARTITION

alt:"alt" height:90px center

alt:"alt" height:140px center

  • Consider the example where \(A[r]\) is the largest element in the array:
  • End of H-PARTITION: \(i = j = r\)
  • In QUICKSORT: \(q = r\)
    • So, recursive call to:
    • QUICKSORT(A, p, q=r)
      • infinite loop

Correctness of Hoare’s Algorithm (1)

We need to prove \(3\) claims to show correctness:

  • Indices \(i\) and \(j\) never reference \(A\) outside the interval \(A[p \dots r]\)
  • Split is always non-trivial; i.e., \(j \neq r\) at termination
  • Every element in \(A[p \dots j] \leq\) every element in \(A[j+1 \dots r]\) at termination

alt:"alt" height:150px center


Correctness of Hoare’s Algorithm (2)

  • Notations:

  • \(k\): \(\#\) of times the while-loop iterates until termination

  • \(i_m\): the value of index i at the end of iteration \(m\)
  • \(j_m\): the value of index j at the end of iteration \(m\)
  • \(x\): the value of the pivot element

  • Note: We always have \(i_1= p\) and \(p \leq j_1 \leq r\) because \(x = A[p]\)


Correctness of Hoare’s Algorithm (3)

Lemma 1: Either \(i_k = j_k\) or \(i_k = j_k+1\) at termination

Proof of Lemma 1:

  • The algorithm terminates when \(i \geq j\) (the else condition).

  • So, it is sufficient to prove that \(i_k – j_k \leq 1\)

  • There are \(2\) cases to consider:

  • Case 1: \(k = 1\), i.e. the algorithm terminates in a single iteration

  • Case 2: \(k > 1\), i.e. the alg. does not terminate in a single iter.

By contradiction, assume there is a run with \(i_k – j_k > 1\)


Correctness of Hoare’s Algorithm (4)

Original correctness claims:

  • Indices \(i\) and \(j\) never reference A outside the interval \(A[p \dots r]\)
  • Split is always non-trivial; i.e., \(j \neq r\) at termination

Proof:

  • For \(k = 1\):
  • Trivial because \(i_1 = j_1 = p\) (see Case 1 in proof of Lemma 2)
  • For \(k > 1\):
  • \(i_k > p\) and \(j_k < r\) (due to the repeat-until loops moving indices)
  • \(i_k \leq r\) and \(j_k \geq p\) (due to Lemma 1 and the statement above)

The proof of claims (a) and (b) complete


Correctness of Hoare’s Algorithm (5)

Lemma 2: At the end of iteration \(m\), where \(m<k\) (i.e. m is not the last iteration), we must have: \(A[p \dots i_m] \leq x\) and \(A[j_m \dots r] \geq x\)

Proof of Lemma 2:

  • Base case: \(m=1\) and \(k>1\) (i.e. the alg. does not terminate in the first iter.)

Ind. Hyp.: At the end of iteration \(m-1\), where \(m<k\) (i.e. m is not the last iteration), we must have: \(A[p \dots i_m-1] \leq x\) and \(A[j_m-1 \dots r] \geq x\)

General case: The lemma holds for \(m\), where \(m < k\)

Proof of base case complete!


Correctness of Hoare’s Algorithm (6)

Original correctness claim:

  • © Every element in \(A[ \dots j] \leq\) every element in \(A[j+ \dots r]\) at termination

Proof of claim ©

  • There are \(3\) cases to consider:
  • Case 1: \(k=1\), i.e. the algorithm terminates in a single iteration
  • Case 2: \(k>1\) and \(i_k = j_k\)
  • Case 3: \(k>1\) and \(i_k = j_k + 1\)

Lomuto’s Partitioning Algorithm (1)

  • Choose a pivot element: \(pivot = x = A[r]\)

alt:"alt" height:100px center

  • Grow two regions:
  • from left to right: \(A[p \dots i]\)
  • from left to right: \(A[i+1 \dots j]\)
    • such that:
    • every element in \(A[p \dots i] \leq pivot\)
    • every element in \(A[i+1 \dots j] > pivot\)

Lomuto’s Partitioning Algorithm (2)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-1)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-2)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-3)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-4)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-5)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-6)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-7)

alt:"alt" height:550px center


Lomuto’s Partitioning Algorithm Ex. (Step-8)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-9)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-10)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-11)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-12)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-13)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-14)

alt:"alt" height:500px center


Lomuto’s Partitioning Algorithm Ex. (Step-15)

alt:"alt" height:500px center


Quicksort with Lomuto’s Partitioning Algorithm

QUICKSORT (A, p, r)
  if p < r then
    q = L-PARTITION(A, p, r)
    QUICKSORT(A, p, q - 1)
    QUICKSORT(A, q + 1, r)
  endif

Initial invocation: QUICKSORT(A,1,n)

alt:"alt" height:150px center


Comparison of Hoare’s & Lomuto’s Algorithms (1)

  • Notation: \(n=r-p+1\)
  • \(pivot=A[p]\) (Hoare)
  • \(pivot=A[r]\) (Lomuto)
  • \(\#\) of element exchanges: \(e(n)\)
  • Hoare: \(0 \geq e(n) \geq \lfloor \frac{n}{2} \rfloor\)
    • Best: \(k=1\) with \(i_1=j_1=p\) (i.e., \(A[p+1 \dots r]>pivot\))
    • Worst: \(A[p+1 \dots p+ \lfloor \frac{n}{2} \rfloor - 1] \geq pivot \geq A[p+ \lceil \frac{n}{2} \rceil \dots r]\)
  • Lomuto : \(1 \leq e(n) \leq n\)
    • Best: \(A[p \dots r -1]>pivot\)
    • Worst: \(A[p \dots r-1] \leq pivot\)

Comparison of Hoare’s & Lomuto’s Algorithms (2)

  • \(\#\) of element comparisons: \(c_e(n)\)

  • Hoare: \(n+1 \leq c_e(n) \leq n+2\)

    • Best: \(i_k=j_k\)
    • Worst: \(i_k=j_k+1\)
  • Lomuto: \(c_e(n)=n-1\)

  • \(\#\) of index comparisons: \(c_i(n)\)

  • Hoare: \(1 \leq c_i(n) \leq \lfloor \frac{n}{2} \rfloor + 1 | (c_i(n)=e(n)+1)\)

  • Lomuto: \(c_i(n)=n-1\)

Comparison of Hoare’s & Lomuto’s Algorithms (3)

  • \(\#\) of index increment/decrement operations: \(a(n)\)

  • Hoare: \(n+1 \leq a(n) \leq n+2 | (a(n)=c_e(n))\)

  • Lomuto: \(n \leq a(n) \leq 2n-1 | (a(n)=e(n)+(n-1))\)

  • Hoare’s algorithm is in general faster

  • Hoare behaves better when pivot is repeated in \(A[p \dots r]\)

  • Hoare: Evenly distributes them between left & right regions

  • Lomuto: Puts all of them to the left region

Analysis of Quicksort (1)

QUICKSORT (A, p, r)
  if p < r then
    q = H-PARTITION(A, p, r)
    QUICKSORT(A, p, q)
    QUICKSORT(A, q + 1, r)
  endif

Initial invocation: QUICKSORT(A,1,n)

alt:"alt" height:150px center

Assume all elements are distinct in the following analysis


Analysis of Quicksort (2)

  • H-PARTITION always chooses \(A[p]\) (the first element) as the pivot.
  • The runtime of QUICKSORT on an already-sorted array is \(\Theta(n^2)\)

Example: An Already Sorted Array

Partitioning always leads to \(2\) parts of size \(1\) and \(n-1\)

alt:"alt" height:450px center


Worst Case Analysis of Quicksort

  • Worst case is when the PARTITION algorithm always returns imbalanced partitions (of size \(1\) and \(n-1\)) in every recursive call.
  • This happens when the pivot is selected to be either the min or max element.
  • This happens for H-PARTITION when the input array is already sorted or reverse sorted
\[ \begin{align*} T(n) &= T(1) + T(n-1) + Θ(n) \\ &= T(n-1) + Θ(n) \\ &= Θ(n2) \end{align*} \]

Worst Case Recursion Tree

\[ T(n) = T(1) + T(n-1) + cn \]

alt:"alt" height:450px center


Best Case Analysis (for intuition only)

  • If we’re extremely lucky, H-PARTITION splits the array evenly at every recursive call
\[ \begin{align*} T(n) &= 2T(n/2) + \Theta(n) \\ &= \Theta(nlgn) \end{align*} \]

(same as merge sort)

  • Instead of splitting \(0.5:0.5\), if we split \(0.1:0.9\) then we need solve following equation.

$$

\begin{align*} T(n) &= T(n/10) + T(9n/10) + \Theta(n) \ &= \Theta(nlgn) \end{align*} $$


“Almost-Best” Case Analysis

alt:"alt" height:500px center


Balanced Partitioning (1)

  • We have seen that if H-PARTITION always splits the array with \(0.1-to-0.9\) ratio, the runtime will be \(\Theta(nlgn)\).

  • Same is true with a split ratio of \(0.01-to-0.99\), etc.

  • Possible to show that if the split has always constant \((\Theta(1))\) proportionality, then the runtime will be \(\Theta(nlgn)\).

  • In other words, for a constant \(\alpha | (0 < \alpha ≤ 0.5)\):

  • \(\alpha–to–(1-\alpha)\) proportional split yields \(\Theta(nlgn)\) total runtime


Balanced Partitioning (2)

  • In the rest of the analysis, assume that all input permutations are equally likely.
  • This is only to gain some intuition
  • We cannot make this assumption for average case analysis
  • We will revisit this assumption later
  • Also, assume that all input elements are distinct.

Balanced Partitioning (3)

  • Question: What is the probability that H-PARTITION returns a split that is more balanced than \(0.1-to-0.9\)?

Balanced Partitioning (4)

Reminder: H-PARTITION will place the pivot in the right partition unless the pivot is the smallest element in the arrays.

Question: If the pivot selected is the mth smallest value \((1 < m ≤ n)\) in the input array, what is the size of the left region after partitioning?

alt:"alt" height:330px center


Balanced Partitioning (5)

  • Question: What is the probability that the pivot selected is the \(m^{th}\) smallest value in the array of size \(n\)?

  • \(1/n\) (since all input permutations are equally likely)

  • Question: What is the probability that the left partition returned by H-PARTITION has size \(m\), where \(1<m<n\)?

  • \(1/n\) (due to the answers to the previous 2 questions)


Balanced Partitioning (6)

  • Question: What is the probability that H-PARTITION returns a split that is more balanced than \(0.1-to-0.9\)?
\[ \begin{align*} Probability &=\sum \limits_{q=0.1n+1}^{0.9n-1}\frac{1}{n} \\ &=\frac{1}{n}(0.9n-1-0.1n-1+1) \\ &= 0.8-\frac{1}{n} \\ & \approx 0.8 \text{ for large n} \end{align*} \]

bg right:50% w:500px


Balanced Partitioning (7)

  • The probability that H-PARTITION yields a split that is more balanced than \(0.1-to-0.9\) is \(80\%\) on a random array.

  • Let \(P_{\alpha>}\) be the probability that H-PARTITION yields a split more balanced than \(\alpha-to-(1-\alpha)\), where \(0 < \alpha \leq 0.5\)

  • Repeat the analysis to generalize the previous result


Balanced Partitioning (8)

  • Question: What is the probability that H-PARTITION returns a split that is more balanced than \(\alpha-to-(1-\alpha)\)?

bg right:40% w:500px

\[ \begin{align*} Probability & =\sum \limits_{q=\alpha n+1}^{(1-\alpha)n-1}\frac{1}{n} \\ & =\frac{1}{n}((1-\alpha)n-1- \alpha n-1+1) \\ & = (1-2\alpha)-\frac{1}{n} \\ & \approx (1-2\alpha) \text{ for large n} \end{align*} \]

Balanced Partitioning (9)

  • We found \(P_{\alpha >}=1-2\alpha\)
  • Ex: \(P_{0.1>}=0.8\) and \(P_{0.01>}=0.98\)
  • Hence, H-PARTITION produces a split
  • more balanced than a
    • \(0.1-to-0.9\) split \(80\%\) of the time
    • \(0.01-to-0.99\) split \(98\%\) of the time
  • less balanced than a
    • \(0.1-to-0.9\) split \(20\%\) of the time
    • \(0.01-to-0.99\) split \(2\%\) of the time

Intuition for the Average Case (1)

  • Assumption: All permutations are equally likely

  • Only for intuition; we’ll revisit this assumption later

  • Unlikely: Splits always the same way at every level

  • Expectation:

  • Some splits will be reasonably balanced

  • Some splits will be fairly unbalanced

  • Average case: A mix of good and bad splits

  • Good and bad splits distributed randomly thru the tree


Intuition for the Average Case (2)

  • Assume for intuition: Good and bad splits occur in the alternate levels of the tree
  • Good split: Best case split
  • Bad split: Worst case split

Intuition for the Average Case (3)

Compare 2-successive levels of avg case vs. 1 level of best case

alt:"alt" h:450px center


Intuition for the Average Case (4)

  • In terms of the remaining subproblems, two levels of avg case is slightly better than the single level of the best case

  • The avg case has extra divide cost of \(\Theta(n)\) at alternate levels

  • The extra divide cost \(\Theta(n)\) of bad splits absorbed into the \(\Theta(n)\) of good splits.

  • Running time is still \(\Theta(nlgn)\)

  • But, slightly larger hidden constants, because the height of the recursion tree is about twice of that of best case.

Intuition for the Average Case (5)

  • Another way of looking at it:
  • Suppose we alternate lucky, unlucky, lucky, unlucky, \(\dots\)
  • We can write the recurrence as:
    • \(L(n) = 2U(n/2) + \Theta(n)\) lucky split (best)
    • \(U(n) = L(n-1) + \Theta(n)\) unlucky split (worst)
  • Solving:
\[ \begin{align*} L(n) & = 2(L(n/2-1) + \Theta(n/2)) + \Theta(n) \\ & = 2L(n/2-1) + \Theta(n) \\ & = Θ(nlgn) \end{align*} \]
  • How can we make sure we are usually lucky for all inputs?

Summary: Quicksort Runtime Analysis (1)

  • Worst case: Unbalanced split at every recursive call
\[ \begin{align*} T(n) & = T(1) + T(n-1) + \Theta(n) \\ T(n) & = \Theta(n2) \end{align*} \]
  • Best case: Balanced split at every recursive call (extremely lucky)
\[ \begin{align*} T(n) & = 2T(n/2) + \Theta(n) \\ T(n) & = \Theta(nlgn) \end{align*} \]

Summary: Quicksort Runtime Analysis (2)

  • Almost-best case: Almost-balanced split at every recursive call
\[ \begin{align*} T(n) &=T(n/10)+T(9n/10)+ \Theta(n) \\ \text{or } T(n) &= T(n/100) + T(99n/100) + Θ(n) \\ \text{or } T(n) &= T(\alpha n) + T((1-\alpha n)+ \Theta(n) \end{align*} \]

for any constant \(\alpha, 0 < \alpha \leq 0.5\)


Summary: Quicksort Runtime Analysis (3)

  • For a random input array, the probability of having a split

  • more balanced than \(0.1 – to – 0.9 : 80\%\)

  • more balanced than \(0.01 – to – 0.99 : 98\%\)
  • more balanced than \(\alpha – to – (1-\alpha) : 1 – 2 \alpha\)

  • for any constant \(\alpha, 0 < \alpha \leq 0.5\)


Summary: Quicksort Runtime Analysis (4)

  • Avg case intuition: Different splits expected at different levels

  • some balanced (good), some unbalanced (bad)

  • Avg case intuition: Assume the good and bad splits alternate

  • i.e. good split -> bad split -> good split -> …

  • \(T(n) = \Theta(nlgn)\)
    • (informal analysis for intuition)

Randomized Quicksort

  • In the avg-case analysis, we assumed that all permutations of the input array are equally likely.
  • But, this assumption does not always hold
  • e.g. What if all the input arrays are reverse sorted?
    • Always worst-case behavior
  • Ideally, the avg-case runtime should be independent of the input permutation.
  • Randomness should be within the algorithm, not based on the distribution of the inputs.
  • i.e. The avg case should hold for all possible inputs

Randomized Algorithms (1)

  • Alternative to assuming a uniform distribution:
  • Impose a uniform distribution
  • e.g. Choose a random pivot rather than the first element
  • Typically useful when:
  • there are many ways that an algorithm can proceed
  • but, it’s difficult to determine a way that is always guaranteed to be good.
  • If there are many good alternatives; simply choose one randomly.

Randomized Algorithms (1)

  • Ideally:
  • Runtime should be independent of the specific inputs
  • No specific input should cause worst-case behavior
  • Worst-case should be determined only by output of a random number generator.

Randomized Quicksort (1)

  • Using Hoare’s partitioning algorithm:
R-QUICKSORT(A, p, r)
  if p < r then
    q = R-PARTITION(A, p, r)
    R-QUICKSORT(A, p, q)
    R-QUICKSORT(A, q+1, r)
R-PARTITION(A, p, r)
  s = RANDOM(p, r)
  exchange A[p] with A[s]
  return H-PARTITION(A, p, r)
  • Alternatively, permuting the whole array would also work
  • but, would be more difficult to analyze

Randomized Quicksort (2)

  • Using Lomuto’s partitioning algorithm:
R-QUICKSORT(A, p, r)
  if p < r then
    q = R-PARTITION(A, p, r)
    R-QUICKSORT(A, p, q-1)
    R-QUICKSORT(A, q+1, r)
R-PARTITION(A, p, r)
  s = RANDOM(p, r)
  exchange A[r] with A[s]
  return L-PARTITION(A, p, r)
  • Alternatively, permuting the whole array would also work
  • but, would be more difficult to analyze

Notations for Formal Analysis

  • Assume all elements in \(A[p \dots r]\) are distinct

  • Let \(n = r – p + 1\)

  • Let \(rank(x) = |{A[i]: p \leq i \leq r \text{ and } A[i] \leq x}|\)

  • i.e. \(rank(x)\) is the number of array elements with value less than or equal to \(x\)

  • \(A=\{5,9,7,6,8,1,4\}\)

  • \(p=5,r=4\)
  • \(rank(5)=3\)
    • i.e. it is the \(3^{rd}\) smallest element in the array

Formal Analysis for Average Case

  • The following analysis will be for Quicksort using Hoare’s partitioning algorithm.

  • Reminder: The pivot is selected randomly and exchanged with \(A[p]\) before calling H-PARTITION

  • Let \(x\) be the random pivot chosen.

  • What is the probability that \(rank(x) = i\) for \(i = 1, 2, \dots n\) ?

  • \(P(rank(x) = i) = 1/n\)


Various Outcomes of H-PARTITION (1)

  • Assume that \(rank(x)=1\)
  • i.e. the random pivot chosen is the smallest element
  • What will be the size of the left partition \((|L|)\)?
  • Reminder: Only the elements less than or equal to \(x\) will be in the left partition.

\(A=\{\overbrace{2}^{p=x=pivot}\underbrace{,}_{\Longrightarrow|L|=1 } 9,7,6,8,5,\overbrace{4}^r\}\)

\(p=2,r=4\) \(pivot=x=2\)

TODO: convert to image...S6_P9


Various Outcomes of H-PARTITION (2)

  • Assume that \(rank(x)>1\)
  • i.e. the random pivot chosen is not the smallest element
  • What will be the size of the left partition \((|L|)\)?
  • Reminder: Only the elements less than or equal to \(x\) will be in the left partition.
  • Reminder: The pivot will stay in the right region after H-PARTITION if \(rank(x)>1\)

\(A=\{\overbrace{2}^{p}, 4 \underbrace{,}_{\Longrightarrow|L|=rank(x)-1}7,6,8,\overbrace{5,}^{pivot}\overbrace{9}^r\}\)

\(p=2,r=4\) \(pivot=x=5\)

TODO: convert to image...S6_P10


Various Outcomes of H-PARTITION - Summary (1)

  • \(x: pivot\)

  • \(|L|: \text{size of left region}\)

  • \(P(rank(x) = i) = 1/n \text{ for } 1 \leq i \leq n\)

  • \(\text{if } rank(x) = 1 \text{ then } |L| = 1\)

  • \(\text{if } rank(x) > 1 \text{ then } |L| = rank(x) - 1\)

  • \(P(|L| = 1) = P(rank(x) = 1) + P(rank(x) = 2)\)

  • \(P(|L| = 1) = 2/n\)

  • \(P(|L| = i) = P(rank(x) = i+1) \text{ for } 1< i < n\)

  • \(P(|L| = i) = 1/n \text{ for } 1< i < n\)


Various Outcomes of H-PARTITION - Summary (2)

alt:"alt" h:450px center


Average - Case Analysis: Recurrence (1)

\(x=pivot\)

\[ \begin{align*} T(n) & = \frac{1}{n}(T(1)+t(n-1) ) & rank:1 \\ & + \frac{1}{n}(T(1)+t(n-1) ) & rank:2 \\ & + \frac{1}{n}(T(2)+t(n-2) ) & rank:3 \\ & \vdots & \vdots \\ & + \frac{1}{n}(T(i)+t(n-i) ) & rank:i+1 \\ & \vdots & \vdots \\ & + \frac{1}{n}(T(n-1)+t(1) ) & rank:n \\ & + \Theta(n) \end{align*} \]

Average - Case Analysis: Recurrence (2)

\[ \begin{align*} T(n) &= \frac{1}{n}\sum \limits_{q=1}^{n-1}(T(q)+T(n-q))+\frac{1}{n}(T(1)+T(n-1))+\Theta(n)\\ & \text{Note: } \frac{1}{n}(T(1)+T(n-1))=\frac{1}{n}(\Theta(1)+O(n^2))=O(n) \\ T(n) &= \frac{1}{n}\sum \limits_{q=1}^{n-1}(T(q)+T(n-q))+\Theta(n) \end{align*} \]

for \(k=1,2,\dots,n-1\) each term \(T(k)\) appears twice once for \(q = k\) and once for \(q = n−k\)

\[ T(n) = \frac{2}{n}\sum \limits_{k=1}^{n-1} T(k)+\Theta(n) \]

Average - Case Analysis -Solving Recurrence: Substitution

  • Guess: \(T(n)=O(nlgn)\)
  • \(T(k) ≤ aklgk\) for \(k<n\), for some constant \(a > 0\)
\[ \begin{align*} T(n) &= \frac{2}{n} \sum \limits_{k=1}^{n-1} T(k)+\Theta(n) \\ & \leq \frac{2}{n} \sum \limits_{k=1}^{n-1} aklgk+\Theta(n) \\ & \leq \frac{2a}{n} \sum \limits_{k=1}^{n-1} klgk+\Theta(n) \end{align*} \]
  • Need a tight bound for \(\sum klgk\)

Tight bound for \(\sum klgk\) (1)

  • Bounding the terms
  • \(\ \sum \limits_{k=1}^{n-1}klgk \leq \sum \limits_{k=1}^{n-1}nlgn = n(n-1)lgn \leq n^2lgn\)
  • This bound is not strong enough because
  • \(T(n) \leq \frac{2a}{n}n^2lgn+\Theta(n)\)
  • \(=2anlgn+\Theta(n)\) \(\Longrightarrow\) couldn’t prove \(T(n) \leq anlgn\)

Tight bound for \(\sum klgk\) (2)

  • Splitting summations: ignore ceilings for simplicity

$$ \sum \limits_{k=1}^{n-1}klgk \leq \sum \limits_{k=1}^{n/2-1}klgk + \sum \limits_{k=n/2}^{n-1}klgk $$

  • First summation: \(lgk < lg(n/2)=lgn-1\)
  • Second summation: \(lgk < lgn\)

Splitting: \(\sum \limits_{k=1}^{n-1}klgk \leq \sum \limits_{k=1}^{n/2-1}klgk + \sum \limits_{k=n/2}^{n-1}klgk\) (3)

\[ \begin{align*} & \sum \limits_{k=1}^{n-1}klgk \leq (lg(n-1))\sum \limits_{k=1}^{n/2-1}k + lgn \sum \limits_{k=n/2}^{n-1}k \\ &= lgn \sum \limits_{k=1}^{n-1}k- \sum \limits_{k=1}^{n/2-1}k \\ &= \frac{1}{2}n(n-1)lgn - \frac{1}{2} \frac{n}{2}(\frac{n}{2}-1) \\ &= \frac{1}{2}n^2lgn - \frac{1}{8}n^2 - \frac{1}{2}n(lgn-1/2) \\ \end{align*} \]
\[ \begin{align*} & \sum \limits_{k=1}^{n-1} klgk \leq \frac{1}{2}n^2lgn-\frac{1}{8}n^2 \ for \ lgn \geq 1/2 \Longrightarrow n \geq \sqrt{2} \end{align*} \]

Substituting: - \(\sum \limits_{k=1}^{n-1}klgk \leq \frac{1}{2}n^2lgn-\frac{1}{8}n^2\) (4)

\[ \begin{align*} T(n) & \leq \frac{2a}{n}\sum \limits_{k=1}^{n-1}klgk+\Theta(n)\\ & \leq \frac{2a}{n}(\frac{1}{2}n^2lgn-\frac{1}{8}n^2)+\Theta(n) \\ & = anlgn - (\frac{a}{4}n-\Theta(n)) \end{align*} \]
  • We can choose a large enough so that \(\frac{a}{4}n \geq \Theta(n)\)
\[ \begin{align*} T(n) & \leq anlgn \\ T(n) & = O(nlgn) \end{align*} \]

Q.E.D.


Medians and Order Statistics

  • ith order statistic: \(i^{th}\) smallest element of a set of \(n\) elements

  • minimum: first order statistic

  • maximum: \(n^{th}\) order statistic

  • median: “halfway point” of the set

\[ \begin{align*} i & = \lfloor \frac{(n+1)}{2} \rfloor \\ \text{ or } \\ i & = \lceil \frac{(n+1)}{2} \rceil \end{align*} \]

Selection Problem

  • Selection problem: Select the \(i^{th}\) smallest of \(n\) elements

  • Naïve algorithm: Sort the input array \(A\); then return \(A[i]\)

  • \(T(n) = \theta(nlgn)\)

    • using e.g. merge sort (but not quicksort)
  • Can we do any better?


Selection in Expected Linear Time

  • Randomized algorithm using divide and conquer

  • Similar to randomized quicksort

  • Like quicksort: Partitions input array recursively

  • Unlike quicksort: Makes a single recursive call

    • Reminder: Quicksort makes two recursive calls
  • Expected runtime: \(\Theta(n)\)

  • Reminder: Expected runtime of quicksort: \(\Theta(nlgn)\)


Selection in Expected Linear Time: Example 1

  • Select the \(2^{nd}\) smallest element:
\[ \begin{align*} A & = \{6,10,13,5,8,3,2,11\} \\ i & = 2 \\ \end{align*} \]
  • Partition the input array:
\[ \begin{align*} A & = \{\underbrace{2,3,5,}_{\text{left subarray} }\underbrace{13,8,10,6,11}_{\text{right subarray}}\} \end{align*} \]
  • make a recursive call to select the \(2^{nd}\) smallest element in left subarray

Selection in Expected Linear Time: Example 2

  • Select the \(7^{th}\) smallest element:
\[ \begin{align*} A & = \{6,10,13,5,8,3,2,11\} \\ i & = 7 \\ \end{align*} \]
  • Partition the input array:
\[ \begin{align*} A & = \{\underbrace{2,3,5,}_{\text{left subarray} }\underbrace{13,8,10,6,11}_{\text{right subarray}}\} \end{align*} \]
  • make a recursive call to select the \(4^{th}\) smallest element in right subarray

Selection in Expected Linear Time (1)

R-SELECT(A,p,r,i)
  if p == r then 
    return A[p];
  q = R-PARTITION(A, p, r)
  k = qp+1;
  if i <= k then 
    return R-SELECT(A, p, q, i);
  else
    return R-SELECT(A, q+1, r, i-k);
\[ \begin{align*} A & = \{ \underbrace{ | }_{p} \dots \leq x \text{(k smallest elements)} \dots \underbrace{ | }_{q} \dots \geq x \dots \underbrace{ | }_{r} \} \\ x & = pivot \end{align*} \]

Selection in Expected Linear Time (2)

\[ \begin{align*} A & = \{ \overbrace{ | }^{p} \underbrace{ \dots \leq x \dots }_{L} \overbrace{ | }^{q} \underbrace{ \dots \geq x \dots }_{R} \overbrace{ | }^{r} \} \\ x & = pivot \end{align*} \]

Selection in Expected Linear Time (2)

  • All elements in \(L \leq\) all elements in \(R\)
  • \(L\) contains:
  • \(|L| = q–p+1\) \(=\) k smallest elements of \(A[p...r]\)
  • if \(i \leq |L| = k\) then
    • search \(L\) recursively for its \(i^{th}\) smallest element
  • else
    • search \(R\) recursively for its \((i-k)^{th}\) smallest element

Runtime Analysis (1)

  • Worst case:
  • Imbalanced partitioning at every level and the recursive call always to the larger partition
\[ \begin{align*} & = \{1,\underbrace{2,3,4,5,6,7,8}_{\text{recursive call}} \} & i & = 8 \\ & = \{2,\underbrace{3,4,5,6,7,8}_{\text{recursive call}} \} & i & = 7 \end{align*} \]

Runtime Analysis (2)

  • Worst case: Worse than the naïve method (based on sorting)
\[ \begin{align*} T(n) &= T(n-1) + \Theta(n) \\ T(n) &= \Theta(n^2) \end{align*} \]
  • Best case: Balanced partitioning at every recursive level
\[ \begin{align*} T(n) &= T(n/2) + \Theta(n) \\ T(n) &= \Theta(n) \end{align*} \]
  • Avg case: Expected runtime – need analysis T.B.D.

Reminder: Various Outcomes of H-PARTITION

  • \(x: pivot\)

  • \(|L|: \text{size of left region}\)

  • \(P(rank(x) = i) = 1/n \text{ for } 1 \leq i \leq n\)

  • \(\text{if } rank(x) = 1 \text{ then } |L| = 1\)

  • \(\text{if } rank(x) > 1 \text{ then } |L| = rank(x) - 1\)

  • \(P(|L| = 1) = P(rank(x) = 1) + P(rank(x) = 2)\)

  • \(P(|L| = 1) = 2/n\)

  • \(P(|L| = i) = P(rank(x) = i+1) \text{ for } 1< i < n\)

  • \(P(|L| = i) = 1/n \text{ for } 1< i < n\)


Average Case Analysis of Randomized Select

  • To compute the upper bound for the avg case, assume that the \(i^{th}\) element always falls into the larger partition.
\[ \begin{align*} A & = \{ \overbrace{ | }^{p} \underbrace{ \dots \leq x \dots }_{Left Partition} \overbrace{ | }^{q} \underbrace{ \dots \geq x \dots }_{Right Partition} \overbrace{ | }^{r} \} \\ x & = pivot \end{align*} \]
  • We will analyze the case where the recursive call is always made to the larger partition
  • This will give us an upper bound for the avg case

Various Outcomes of H-PARTITION

alt:"alt" h:450px center


Average-Case Analysis of Randomized Select (1)

\[ \text{Recall:} P(|L|=i) = \begin{cases} 2/n & \text{for } i=1 \\ 1/n & \text{for } i=2,3,\dots,n-1 \end{cases} \]

Upper bound: Assume \(i^{th}\) element always falls into the larger part.

\[ \begin{align*} T(n) &\leq \frac{1}{n}T(max(1,n-1))+\frac{1}{n}\sum \limits_{q=1}^{n-1}T(max(q,n-q))+O(n) \\ Note: & \frac{1}{n}T(max(1,n-1)) = \frac{1}{n}T(n-1)=\frac{1}{n}O(n^2) = O(n) \\ \therefore \text{(3 dot mean therefore) } & T(n) \leq \frac{1}{n}\sum \limits_{q=1}^{n-1}T(max(q,n-q))+O(n) \end{align*} \]

Average-Case Analysis of Randomized Select (2)

\[ \begin{align*} \therefore T(n) \leq \frac{1}{n}\sum \limits_{q=1}^{n-1}T(max(q,n-q))+O(n) \end{align*} \]
\[ max(q, n–q) = \begin{cases} q & \text{ if } q \geq \lceil n/2 \rceil \\ n-q & \text{ if } q < \lceil n/2 \rceil \\ \end{cases} \]
  • \(n\) is odd: \(T(k)\) appears twice for \(k=\lceil n/2 \rceil+1,\lceil n/2 \rceil+2,\dots,n–1\)
  • \(n\) is even:\(T(\lceil n/2 \rceil)\) appears once \(T(k)\) appears twice for \(k = \lceil n/2 \rceil +1, \lceil n/2 \rceil+2,\dots,n–1\)

Average-Case Analysis of Randomized Select (3)

  • Hence, in both cases:
\[ \begin{align*} \sum \limits_{q=1}^{n-1} T(max(q,n-q))+O(n) & \leq 2\sum \limits_{q=\lceil n/2 \rceil}^{n-1} T(q)+O(n) \\ \therefore T(n) & \leq \frac{2}{n} \sum \limits_{q=\lceil n/2 \rceil}^{n-1}T(q)+O(n) \end{align*} \]

Average-Case Analysis of Randomized Select (4)

\[ \begin{align*} T(n) & \leq \frac{2}{n} \sum \limits_{q=\lceil n/2 \rceil}^{n-1}T(q)+O(n) \end{align*} \]
  • By substitution guess \(T(n) = O(n)\)
  • Inductive hypothesis: \(T(k) \leq ck, \forall k<n\)
\[ \begin{align*} T(n) & \leq \frac{2}{n} \sum \limits_{q=\lceil n/2 \rceil}^{n-1}ck+O(n) \\ & = \frac{2c}{n} \Bigg(\sum \limits_{k=1}^{n-1}k-\sum \limits_{k=1}^{\lceil n/2 \rceil-1}k \Bigg)+ O(n) \\ & = \frac{2c}{n} \Bigg(\frac{1}{2}n(n-1)-\frac{1}{2} \lceil \frac{n}{2} \rceil \bigg( \frac{n}{2}-1 \bigg) \Bigg)+ O(n) \end{align*} \]

Average-Case Analysis of Randomized Select (5)

\[ \begin{align*} T(n)& \leq \frac{2c}{n} \Bigg(\frac{1}{2}n(n-1)-\frac{1}{2} \lceil \frac{n}{2} \rceil \bigg( \frac{n}{2}-1 \bigg) \Bigg)+ O(n) \\ & \leq c(n-1)-\frac{c}{4}n+\frac{c}{2}+O(n) \\ & = cn - \frac{c}{4}n - \frac{c}{2} + O(n) \\ & = cn - \Bigg( \bigg( \frac{c}{4}n+\frac{c}{2}\bigg) + O(n) \Bigg) \\ & \leq cn \end{align*} \]
  • since we can choose c large enough so that \((cn/4+c/2 )\) dominates \(O(n)\)

Summary of Randomized Order-Statistic Selection

  • Works fast: linear expected time

  • Excellent algorithm in practise

  • But, the worst case is very bad: \(\Theta(n^2)\)

  • Blum, Floyd, Pratt, Rivest & Tarjan[1973] algorithms are runs in linear time in the worst case.

  • Generate a good pivot recursively


Selection in Worst Case Linear Time

//return i-th element in set S with n elements
SELECT(S, n, i)  

  if n <= 5 then

    SORT S and return the i-th element

  DIVIDE S into ceil(n/5) groups
  //first ceil(n/5) groups are of size 5, last group is of size n mod 5

  FIND median set M={m ,, m_ceil(n/5)}
  // m_j : median of j-th group

  x = SELECT(M,ceil(n/5),floor((ceil(n/5)+1)/2))

  PARTITION set S around the pivot x into L and R

  if i <= |L| then
    return  SELECT(L, |L|, i)
  else
    return  SELECT(R, n|L|, i|L|)

Selection in Worst Case Linear Time - Example (1)

  • Input: Array \(S\) and index \(i\)
  • Output: The \(i^{th}\) smallest value
\[ \begin{array}{ccc} 25 & 9 & 16 & 8 & 11 & 27 & 39 & 42 & 15 & 6 32 & 14 & 36 & 20 & 33 & 22 & 31 & 4 & 17 & 3 & 30 & 41 \\ 2 & 13 & 19 & 7 & 21 & 10 & 34 & 1 & 37 & 23 & 40 & 5 & 29 & 18 & 24 & 12 & 38 & 28 & 26 & 35 & 43 \end{array} \]

Selection in Worst Case Linear Time - Example (2)

Step 1: Divide the input array into groups of size \(5\)

\[ \overbrace{ \begin{array}{ccc} 25 & 9 & 16 & 8 & 11 \\ 27 & 39 & 42 & 15 & 6 \\ 32 & 14 & 36 & 20 & 33 \\ 22 & 31 & 4 & 17 & 3 \\ 30 & 41 & 2 & 13 & 19 \\ 7 & 21 & 10 & 34 & 1 \\ 37 & 23 & 40 & 5 & 29 \\ 18 & 24 & 12 & 38 & 28 \\ 26 & 35 & 43 \end{array} }^{\text{group size}=5} \]

Selection in Worst Case Linear Time - Example (3)

Step 2: Compute the median of each group (\(\Theta(n)\))

\[ \begin{array}{ccc} 25 & 16 & \overbrace{11}^{Medians} & 8 & 9 \\ 39 & 42 & 27 & 6 & 15 \\ 36 & 33 & 32 & 20 & 14 \\ 22 & 31 & 17 & 3 & 4 \\ 41 & 30 & 19 & 13 & 2 \\ 21 & 34 & 10 & 1 & 7 \\ 37 & 40 & 29 & 23 & 5 \\ 38 & 28 & 24 & 12 & 18 \\ & 26 & 35 & 43 \end{array} \]
  • Let \(M\) be the set of the medians computed:
  • \(M = \{11, 27, 32, 17, 19, 10, 29, 24, 35\}\)

Selection in Worst Case Linear Time - Example (4)

Step 3: Compute the median of the median group \(M\)

\(x \leftarrow SELECT(M,|M|,\lfloor (|M|+1)/2 \rfloor)\) where \(|M|=\lceil n/5 \rceil\)

  • Let \(M\) be the set of the medians computed:

  • \(M = \{11, 27, 32, 17, 19, 10, 29, \overbrace{24}^{Median}, 35\}\)

  • \(Median = 24\)

  • The runtime of the recursive call: \(T(|M|)=T(\lceil n/5 \rceil)\)


Selection in Worst Case Linear Time - Example (5)

Step 4: Partition the input array \(S\) around the median-of-medians \(x\)

\[ \begin{array}{ccc} 25 & 9 & 16 & 8 & 11 & 27 & 39 & 42 & 15 & 6 32 & 14 & 36 & 20 & 33 & 22 & 31 & 4 & 17 & 3 & 30 & 41 \\ 2 & 13 & 19 & 7 & 21 & 10 & 34 & 1 & 37 & 23 & 40 & 5 & 29 & 18 & 24 & 12 & 38 & 28 & 26 & 35 & 43 \end{array} \]

Partition \(S\) around \(x = 24\)

Claim: Partitioning around x is guaranteed to be well-balanced.


Selection in Worst Case Linear Time - Example (6)

  • \(M\) : Median, \(M^*\) : Median of Medians
\[ \begin{array}{ccc} 41 & 30 & \overbrace{19}^{M} & 13 & 2 \\ 21 & 34 & 10 & 1 & 7 \\ 22 & 31 & 17 & 3 & 4 \\ 25 & 16 & 11 & 8 & 9 \\ 38 & 28 & \overbrace{24}^{M^*} & 12 & 18 \\ 36 & 33 & 32 & 20 & 14 \\ 37 & 40 & 29 & 23 & 5 \\ 39 & 42 & 27 & 6 & 15 \\ & 26 & 35 & 43 \end{array} \]
  • About half of the medians greater than \(x=24\) (about \(n/10\))

Selection in Worst Case Linear Time - Example (7)

alt:"alt" h:500px center


Selection in Worst Case Linear Time - Example (8)

alt:"alt" h:500px center


Selection in Worst Case Linear Time - Example (9)

\[ S = \begin{array}{ccc} \{ 25 & 9 & 16 & 8 & 11 & 27 & 39 & 42 & 15 & 6 32 & 14 & 36 & 20 & 33 & 22 & 31 & 4 & 17 & 3 & 30 & 41 \\ 2 & 13 & 19 & 7 & 21 & 10 & 34 & 1 & 37 & 23 & 40 & 5 & 29 & 18 & 24 & 12 & 38 & 28 & 26 & 35 & 43 \} \end{array} \]
  • Partitioning \(S\) around \(x = 24\) will lead to partitions of sizes \(\sim 3n/10\) and \(\sim 7n/10\) in the worst case.

Step 5: Make a recursive call to one of the partitions

if i <= |L| then 
  return SELECT(L,|L|,i)
else 
  return SELECT(R,n-|L|,i-|L|)

Selection in Worst Case Linear Time

//return i-th element in set S with n elements
SELECT(S, n, i)  

  if n <= 5 then

    SORT S and return the i-th element

  DIVIDE S into ceil(n/5) groups
  //first ceil(n/5) groups are of size 5, last group is of size n mod 5

  FIND median set M={m ,, m_ceil(n/5)}
  // m_j : median of j-th group

  x = SELECT(M,ceil(n/5),floor((ceil(n/5)+1)/2))

  PARTITION set S around the pivot x into L and R

  if i <= |L| then
    return  SELECT(L, |L|, i)
  else
    return  SELECT(R, n|L|, i|L|)

Choosing the Pivot (1)

  1. Divide S into groups of size 5

alt:"alt" h:450px center


Choosing the Pivot (2)

  • Divide S into groups of size 5
  • Find the median of each group

alt:"alt" h:450px center


Choosing the Pivot (3)

  • Divide S into groups of size 5
  • Find the median of each group
  • Recursively select the median x of the medians

alt:"alt" h:450px center


Choosing the Pivot (4)

  • At least half of the medians \(\geq x\)
  • Thus \(m = \lceil \lceil n/5 \rceil /2 \rceil\) groups contribute 3 elements to R except possibly the last group and the group that contains \(x\), \(|R|\geq 3(m–2)\geq \frac{3n}{10}–6\)

alt:"alt" h:400px center


Choosing the Pivot (5)

  • Similarly \(|L| \geq \frac{3n}{10}– 6\)
  • Therefore, SELECT is recursively called on at most \(n-(\frac{3n}{10}-6)=\frac{7n}{10}+6\) elements

alt:"alt" h:400px center


Selection in Worst Case Linear Time (1)

alt:"alt" h:500px center


Selection in Worst Case Linear Time (2)

  • Thus recurrence becomes
  • \(T(n) \leq T \big( \lceil \frac{n}{5} \rceil \big) + T\big( \frac{7n}{10}+6 \big) + \Theta(n)\)
  • Guess \(T(n)=O(n)\) and prove by induction
  • Inductive step:
\[ \begin{align*} T(n) & \leq c \lceil n/5 \rceil + c(7n/10+6)+\Theta(n) \\ & \leq cn/5 + c + 7cn/10 + 6c + \Theta(n) \\ & = 9cn/10 + 7c + \Theta(n) \\ & = cn - [c(n/10-7)-\Theta(n)] \leq cn &\text{( for large c)} \end{align*} \]
  • Work at each level of recursion is a constant factor \((9/10)\) smaller

References


\(-End-Of-Week-3-Course-Module-\)


Last update: October 6, 2022
Back to top