Angorithm4 Webinar #4
Cohost by Jiawei Wang 2021-11-5
1. Main Falcon
2. Comparision Sort(II) - QuickSort
i. Description
The Quicksort algorithm has a worst-case running time of
O(N^2)
on any input array of number.
Despite this slow worst-case running time, Quicksort is often
the best practical choice for sorting because it is remarkbly efficient
on the average: Its expected running time is
O(nlogn)
and the constant factors hidden
in the O(nlogn) notation are quite small.
- Designed by Hoare in 1962
- Sort in Place (No extra storiage needed)
- Three or more times faster than Merge Sort (Merge guarentee O(N))
- Most good sorting algorithms that you will find are based on quicksort
- But not the Theoretically fastest sorting algorithm (Will be proved in the next Webinar)
int Partition(vector<int> &A, int p, int q) {
// (p, i) (i+1, j)
int x = A[p];
int i = p;
for (int j = p + 1; j <= q; j++) {
if(A[j] <= x) {
= i + 1;
i (A[i], A[j]);
swap}
}
(A[p], A[i]);
swapreturn i;
}
void QuickSort(vector<int> &A, int p, int r) {
if (p < r) {
int q = Partition(A, p, r);
(A, p, q-1);
QuickSort(A, q+1, r);
QuickSort}
}
Partition(A, p, q)
find the rank ofA[p]
in region[p, q]
- Initial call:
QuickSort(A, 0, n-1)
5 2 6 1
5 2 1 6 1 2 5 6
ii. Analysis
Key: Good / Bad Partition
1. Worst-Case Partitioning
The worst-case behavior for quicksort occurs when the input is
sorted or reverse-sorted.
At that time, the partition routine produce one subproblem with
n-1
element and one with 0
element
T(N) = T(N-1) + O(N)
->
O(N^2)
2. Best-Case Partitioning
- When Best-Case ?
Back to 1. Worse-Case
T(N) = max(T(q) + T(N-q-1)) + O(N)
We use substitution method, asssume that
T(N) <= cN^2
for some constant
c
T(N) <= max(c q^2 + c (n-q-1)^2) + O(N)
T(N) <= c max(q^2 + (n-q-1)^2) + O(N)
f'(q) = 4q - 2n + 2
f''(q) = 4
-> f'(q) = 0
when
q = n/2 - 1/2 = (n-1)/2
and that time get the
minimum
Which subproblem’s size no more than
n/2
T(N) = 2T(N/2) + O(N)
-> O(NlogN)
3.
Randomized Quicksort -> proof the avg Time Complexity is
O(NlogN)
iii. Example (LeetCode 215)
nums = [3,2,1,5,6,4], k = 2
Output: 5
using namespace::std;
class Solution {
public:
// #1 using priority queue
int findKthLargest(vector<int>& nums, int k) {
<int> q(nums.begin(), nums.end());
priority_queuefor (int i = 0; i < k - 1; ++i) {
.pop();
q}
return q.top();
}
// #2 using quick sort partition
int findKthLargest2(vector<int>& nums, int k) {
int left = 0; int right = nums.size() - 1;
while (true) {
int desc = Partition(nums, left, right);
if (desc == k-1)
return nums[desc];
if (desc < k-1) {
// nums[pos-1] is too large
= desc + 1;
left } else {
= desc - 1;
right }
}
}
private:
int Partition(vector<int> &A, int p, int q) {
// [p, i] [i+1, q]
// ----------->
// descending order
int x = A[p];
int i = p;
for (int j = p + 1; j <= q; j++) {
if(A[j] >= x) {
= i + 1;
i (A[i], A[j]);
swap}
}
(A[p], A[i]);
swapreturn i;
}
};