CSCE 221 Chapter 10

From Notes
Jump to navigation Jump to search

« previous | Tuesday, March 8, 2011 | next »


Divide and Conquer (D&C)

(See wikipedia:Master Theorem→)


Recurrence Relation

  • represents the time to solve a problem of size
    • can be separated into several subproblems if divided unequally (e.g. )
  • represents the number of subproblems that we'll have to recurse over
  • represents the size of subproblems we'll recurse over
  • represents the time to partition into subproblems
  • represents the time to combine subproblem solutions to get a total solution

(not in chapter)

Example

Multiply two -bit integers:

  1. Divide: split I and J into high- and low- order bits
  2. Multiply parts and adding:
  3. Recurrence Relation:

Merge Sort D&C

  1. Divide: divide into and
  2. Recurse: divide and recursively until base case is of size 0 or 1
  3. Conquer: combine solutions of and
Algorithm mergeSort(Sequence S,Comparator c) {
  if (S.size() > 1) {
    (S_1, S_2) = partition(S, n/2);
    mergeSort(S_1);
    mergeSort(S_2);
    S := merge(S_1,S_2);
  }
}

Algorithm merge(Sequence A, Sequence B) {
  S = Sequence();
  while (!A.isEmpty() && !B.isEmpty()) {
    if (A.first().element() < B.first().element()) {
      S.insertLast(A.remove(A.first()));
    } else {
      S.insertLast(B.remove(B.first()));
    }
  }
  while (!A.isEmpty()) {
    S.insertLast(A.remove(A.first()));
  }
  while (!B.isEmpty()) {
    S.insertLast(B.remove(B.first()));
  }
  return S;
}

Analysis

Depth # Sequences Size of each Sequence
0 1
1 2
2 4

The merge() algorithm takes time, where is the size of and .

Time function recurrence relation:

forms a binary tree of height , where an function is called at each level. Therefore .

Brute force analysis:

Therefore, merge sort is


Parallel Algorithm

D&C is very useful for parallel processing:

Quick Sort

Thursday, March 10, 2011

  1. Divide: Pick a random element called a pivot and partition into elements less than , elements equal to , and elements greater than .
  2. Recur: Sort and
  3. Conquer: Combine/join , , and .


Algorithm partition(Sequence S, Position p) {
  Sequence L, E, G;
  x = S.remove(p);
  while (!S.isEmpty()) {
    y = S.remove(S.first());
    if (y < x) L.insertLast(y);
    else if (y == x) E.insertLast(y);
    else G.insertLast(y);
  }
  // sort L, E, and G
  return merge(L, E, G);
}

Analysis

Best Case (we pick the middle element every time; ):

Worst Case (we pick smallest or largest element every time):


Summary of Comparison-based Algorithms

Algorithm Time Notes
selection-sort in-place, slow (good for small inputs)
insertion sort in-place, slow (good for small inputs)
quick-sort in-place, randomized, fastest (good for large inputs)
heap-sort in-place, fast (good for large inputs)
merge-sort sequential data access, fast (good for large inputs)


Bucket-Sort

Not comparison-based and uns in linear time.

Input: A sequence of key/value paired items with key range 0-9 (inclusive).

Lexicographic sort (sort by key, then by item)

  1. Create a bucket array of size 10 (chained array like what was used for dictionaries)
  2. Stick items in their buckets depending on key element
  3. pull items out of bucket (don't worry about arranging by value element)

In General:

  • Keys range from [0, N−1]
  • Create a bucket array of size
  • Phase 1: Empty the sequence by moving each item into its bucket
  • Phase 2: For i=0..N-1, move the items to the end of the sequence


def bucketSort s, n
  b = Array.new(n)
  while !s.isEmpty do
    f = s.first
    (k,o) = s.remove f
    B[k].insertLast (k,o)
  end
  for 0.upto(N-1) do |i|
    while !B[i].isEmpty do
      f = B[i].first
      (k,o) = B[i].remove f
      s.insertLast (k,o)
    end
  end
end

In order to sort lexicographically, we bucket-sort based on the last element in the tuple, then bucket sort in reverse up to the 1st tuple element. The reason this works is because bucket-sort is stable

Example

Sort (3,3) (1,5) (2,5) (1,2) (2,3) (1,7) (3,2) (2,2):

  1. bucket-sort by 2nd: (1,2) (3,2) (2,2) (3,3) (2,3) (1,5) (2,5) (1,7)
  2. bucket-sort by 1st: (1,2) (1,5) (1,7) (2,2) (2,3) (2,5) (3,2) (3,3)


Radix Sort

  1. Break an integer into digit tuples:
    e.g. 746 → (7,4,6); 10 → (0,1,0)
  2. Perform bucket-sort on the ones place, tens place, hundreds place, etc.
  3. et voila!
def radixSort s, n
  # s is a sequence of d-tuples such that each place in the tuple is between 0 and n-1
  for d.downto(1) do |i|
    # set key k of each item of s to i-th dimension x_i
    bucketSort(s,n)
  end
end

Runs in time, where is the number of "digits" (thus number of iterations), is the number of items to sort, and is the number of buckets.

Example

In computers, we use binary numbers:

  • Bits can be 0 or 1
    We can look at many bits. We'll call this number (i.e. : 00, 01, 10, 11)
  • , where is the number of bits in an integer.

Now the running time is . The best value to choose for would be one that balances and somehow.



Thursday, March 24, 2011

Balance and for -bit binary integers:


Selection

Tuesday, March 29, 2011

Choose the smallest element from an array (also called order statistics):

  • Minimum: — 1st order statistic
  • Maximum: — nth order statistic
  • Median:

Naïve solution: sort and select th item.

Linear Looking

Algorithm minimum(A) {
  m = A[1];
  for i in 2..n {
    M = min(m, A[i]);
  }
  return m;
}

Runs in time. (no better)

If we want to find the th smallest element, we have to perform k scans, so

Quick-select

Randomized selection algorithm based on "prune-and-search" paradigm (similar to D&Q)

Prune: pick a pivot element x and partition S into subsets less, equal, and greater.

Search: Depending on , answer must be in only one of those subsets. Recurse on that half only

def partition S, p
  # input: Sequence (S) position (p) of pivot
  # output: three subsequences based on pivot value: L (less than), E (equal to), and G (greater than)

  l = e = g = Sequence.new
  x = s.remove(p)
  while !s.isEmpty? do
    y = s.remove(s.first)
    if y < x do
      l.insertLast(y)
    else if y == x do
      e.insertLast(y)
    else do
      g.insertLast(y)
    end
  end
  return l,e,g
end

Runs in Best and Average; Worst case.


Deterministic Selection

(See wikipedia:Selection algorithm#Linear general selection algorithm - Median of Medians algorithm→)

Solves in worst-case

Idea: recursively use the selection algorithm itself to find a good pivot for quick-select:

  1. Divide into sets of 5 each
  2. Find a median in each set.
  3. Create a sequence of all the medians of the chunks-of-five
  4. Recursively call this algorithm on the sequence of medians.

Analysis

columns, bigger/smaller than Median of Medians (MoM)

elements bigger/smaller than MoM.