Algorithm Design Techniques
In earlier posts, I went through the insertion sort and the selection sort algorithms. They both use the incremental approach. Each step of the algorithms sorts one element, and thus the algorithms solve the problem incrementally.
The divide-and-conquer is another approach. It includes 3 steps that are executed recursively until the problem is solved:
- Divide the problem into smaller instances of the same problem.
- Conquer or solve the smaller problems.
- Combine the solutions to the smaller problems into the solution for the original problem.
Merge Sort
The merge sort follows the divide-and-conquer approach closely. See section 2.3.1 of Introduction to Algorithms. In each recursion step, a merge sort operates the following 3 steps:
- Divide the n-element sequence to be sorted into two sub-sequences of n/2 elements each.
- Sort the two sub-sequences by comparing the two top elements recursively.
- Merge the two sorted sub-sequences to produce the sorted answer.
Clearly, the merge sort uses the divide-and-conquer approach because it involves applying the algorithm recursively following the divide-and-conquer steps.
The merge algorithm merges two sorted lists into one by comparing the front elements of each list. The smaller element (if the two elements are the same, then either element) gets appended to the one new sorted list. Repeat this until one of the list is empty. The non-empty list is appended to the new sorted list. After this point the two sorted lists are now merged into one.
Analyzing Divide-and-Conquer Algorithms
Because algorithms that take a divide-and-conquer approach are recursive in nature, we describe their running times by a recurrence equation or recurrence. We look at the 3 steps (divide-conquer-combine) of an algorithm and derive the recurrence by adding the running times for each step. Let T(n) be the running time on a problem of size n. In merge sort the recurrence is
- Divide the problem into 2:
- Running time: constant
- Number of executions: 1
- Recurrence: Θ(1)
- Sort the two sub-sequences:
- Running time:T(n/2)
- Number of executions:2
- Recurrence: 2T(n/2)
- Merge the two sorted sub-sequences:
- Running time: Θ(n)
- Number of executions: 1
- Recurrence: Θ(n)
Therefore, the recurrence for a merge sort when n > 1 is
Θ(1) + 2T(n/2) + Θ(n) = 2T(n/2) + Θ(n)
because Θ(1) + Θ(n) = Θ(n).
Bam! We got a sort algorithm that runs much faster than insertion sort! Cool right? Let’s code it in OCaml in both imperative and functional style!
Leave a Reply