|
#include <algorithm> // for std::swap |
|
#include <cassert> |
|
// #include <queue> |
|
#include <stack> |
|
#include "sorting.h" |
|
|
|
/* |
|
* Quick sort: O(n * log(n)) |
|
*/ |
|
unsigned int partition(int list[], unsigned int left, unsigned int right) |
|
{ |
|
// The j is moved anyway. The i is moved if the element at i > p. |
|
// -----+---+---------------------------------+-------------+---+ |
|
// ... | l | ............................... | .. i,j<- .. | r | |
|
// -----+---+---------------------------------+-------------+---+ |
|
// | p | | ... > p ....... | |
|
// |
|
// Stop moving i if the element at i <= p. j is moved anyway. |
|
// Make sure the next(right) element of i is > p. |
|
// -----+---+-------------------------+---+---+-------------+---+ |
|
// ... | l | ....................... | j | i | .. i,j<- .. | r | |
|
// -----+---+-------------------------+---+---+-------------+---+ |
|
// | p | |<=p| ... > p ....... | |
|
// |
|
// Swap elements at i and j when element j > p (before swapping). |
|
// -----+---+-----------+---+---+---------+---+-------------+---+ |
|
// ... | l | ......... | | j | ....... | i | .. i,j<- .. | r | |
|
// -----+---+-----------+---+---+---------+---+-------------+---+ |
|
// | p | | >p| ..<=p.. |<=p| ... > p ....... | |
|
// |
|
// Swap elements at i and j when element j > p (after swapping). |
|
// -----+---+-----------+---+---+---------+---+-------------+---+ |
|
// ... | l | ......... | | j | ....... | i | .. i,j<- .. | r | |
|
// -----+---+-----------+---+---+---------+---+-------------+---+ |
|
// | p | |<=p| ..<=p.. |> p| ... > p ....... | |
|
// |
|
// After swapping, move i. Remember that j is moved anyway. |
|
// The next(right) element of j must be <= p after first swapping. |
|
// -----+---+-----------+---+---+-----+---+---+-------------+---+ |
|
// ... | l | ......... | j | | ... | i | | .. i,j<- .. | r | |
|
// -----+---+-----------+---+---+---------+---+-------------+---+ |
|
// | p | |<=p| ..<=p.. |> p| ... > p ....... | |
|
// |
|
// ... |
|
// ... |
|
// Swap elements at i and j again until element j > p |
|
// -----+---+-----+---+-----+---+-----+---+---+-------------+---+ |
|
// ... | l | ... | j | ... | | ... | i | | .. i,j<- .. | r | |
|
// -----+---+-----+---+-----+---+-----+---+---+-------------+---+ |
|
// | p | | >p| ..<=p.. | ..<=p.. | ....... > p ....... | |
|
// |
|
// ... |
|
// ... |
|
// Stop moving j down to left: |
|
// -----+---+------------------+---+----------+-------------+---+ |
|
// ... | j | ................ | i |..........| .. i,j<- .. | r | |
|
// -----+---+------------------+---+----------+-------------+---+ |
|
// | p | ...... <=p ..... |<=p| .......... > p ........... | |
|
// |
|
// Swap elements at left and i: |
|
// -----+---+------------------+---+----------+-------------+---+ |
|
// ... | j | ................ | i |..........| .. i,j<- .. | r | |
|
// -----+---+------------------+---+----------+-------------+---+ |
|
// |<=p| ...... <=p ..... | p | .......... > p ........... | |
|
int& pivot = list[left]; |
|
unsigned int i = right; |
|
for (unsigned int j = right; j >= left + 1 ; --j) { |
|
if (list[j] > pivot) { |
|
std::swap(list[j], list[i]); |
|
--i; |
|
} |
|
} |
|
std::swap(list[i], pivot); |
|
return i; |
|
|
|
// int& pivot = list[right]; |
|
// unsigned int i = left; // Index of the place for swapping. |
|
// for (unsigned int j = left ; j <= right - 1 ; ++j) { |
|
// if (list[j] <= pivot) { |
|
// std::swap(list[i], list[j]); |
|
// ++i; |
|
// } |
|
// } |
|
// std::swap(list[i], pivot); |
|
// return i; |
|
} |
|
|
|
// -----+---+-----------+---+-----+---+----------+---+----- |
|
// ... | l | .. ->i .. | i | ... | j | .. j<- ..| r | ... |
|
// -----+---+-----------+---+-----+---+----------+---+----- |
|
// | p | .. <=p .. | >p| ... |<=p| .... >p .... | |
|
// | .... <=p .... | |
|
// 1. Keep movinj j to left til finding one element <= p or j = i |
|
// 2. Keep moving i to right til finding one element > p or i = j |
|
// 3. Swap i and j iteratively until j = i. |
|
// 4. Finally, the p should be swapped with an element whose next is >p, |
|
// which is the element at j. |
|
// unsigned int partition(int list[], unsigned int left, unsigned int right) |
|
// { |
|
// assert(left <= right); |
|
// int& pivot = list[left]; |
|
// unsigned int i = left; |
|
// unsigned int j = right; |
|
// while (i < j) { |
|
// // -----+---+-----------+------+----------+---+----- |
|
// // ... | l | .. ->i .. | i, j | .. j<- ..| r | ... |
|
// // -----+---+-----------+------+----------+---+----- |
|
// // | p | .. <=p .. | >p | .... >p .... | |
|
// // Consider the above case, if we move i before j, the p will be |
|
// // swapped with one element > p, and the list will be: |
|
// // | >p | .. <=p .. | p | .. >p .. | |
|
// // It's obviously wrong! The p should be swapped with an element whose next |
|
// // is > p and it is own value <= p, instead of the one whose value is > p. |
|
// if (list[j] > pivot) { |
|
// --j; |
|
// } else if (list[i] <= pivot) { |
|
// ++i; |
|
// } else { |
|
// std::swap(list[i], list[j]); |
|
// } |
|
// } |
|
// std::swap(list[i], pivot); // Currently, i = j. |
|
// return j; |
|
// } |
|
|
|
// -----+---+-----------+---+-----+---+----------+---+----- |
|
// ... | l | .. ->i .. | i | ... | j | .. j<- ..| r | ... |
|
// -----+---+-----------+---+-----+---+----------+---+----- |
|
// | p | .. <=p .. | >p| ... |<=p| .... >p .... | |
|
// | .... <=p .... | |
|
// 1. Keep moving i to right til finding one element > p |
|
// 2. Keep movinj j to left til finding one element <= p |
|
// 3. Swap i and j iteratively until j >= i. |
|
// 4. Finally, the p should be swapped with an element whose next is >p, |
|
// which is the element at j. |
|
// unsigned int partition(int list[], unsigned int left, unsigned int right) |
|
// { |
|
// assert(left <= right); |
|
// int& pivot = list[left]; |
|
// unsigned int i = left; |
|
// unsigned int j = right; |
|
// while (1) { |
|
// while(list[i] <= pivot && i < right) { |
|
// ++i; |
|
// } |
|
// while(list[j] > pivot && j > left) { |
|
// --j; |
|
// } |
|
// // Stop when j > i: |
|
// // -----+---+-----------+---+---+----------+---+----- |
|
// // ... | l | .. ->i .. | j | i | .. j<- ..| r | ... |
|
// // -----+---+-----------+---+---+----------+---+----- |
|
// // | p | .. <=p .. |<=p| >p| .... >p .... | |
|
// // |
|
// // Stop when i = j: |
|
// // -----+---+-----------+---------+----- |
|
// // ... | l | .. ->i .. | i, j, r | ... |
|
// // -----+---+-----------+---------+----- |
|
// // | p | .. <=p .. | <=p | |
|
// if (i >= j) { |
|
// break; |
|
// } |
|
// std::swap(list[i], list[j]); |
|
// } |
|
// std::swap(list[j], pivot); |
|
// return j; |
|
// } |
|
|
|
// Go through all list[left...right]: Pick the left most as the pivot. |
|
// If the element is < pivot, then throw it into "lessequal" array. Otherwise, |
|
// throw it into "greater" array. Finally, we return the concatenated array |
|
// that is lessequal + [pivot] + greater. |
|
// unsigned int partition(int list[], unsigned int left, unsigned int right) |
|
// { |
|
// assert(left <= right); |
|
// int& pivot = list[left]; |
|
// const unsigned int size = right - left + 1; |
|
// |
|
// int lessequal[size]; |
|
// unsigned int l = 0; // Size of the lessequal array. |
|
// |
|
// int greater[size]; |
|
// unsigned int g = 0; // Size of the greater array. |
|
// |
|
// for (unsigned int i = left + 1 ; i <= right ; ++i) { |
|
// if (list[i] < pivot) { |
|
// lessequal[l] = list[i]; |
|
// ++l; |
|
// } else { |
|
// greater[g] = list[i]; |
|
// ++g; |
|
// } |
|
// } |
|
// |
|
// lessequal[l] = pivot; |
|
// ++l; |
|
// |
|
// assert(g + l == size); |
|
// |
|
// // Overwrite list[left...right] by the lessequal and greater. |
|
// for (unsigned int i = left ; i <= right ; ++i) { |
|
// unsigned int k = i - left; |
|
// list[i] = (k < l) ? lessequal[k] : greater[k - l]; |
|
// } |
|
// // unsigned int k = 0; |
|
// // for (unsigned int i = left ; i <= right ; ++i, ++k) { |
|
// // list[i] = (k < l) ? lessequal[k] : greater[k - l]; |
|
// // } |
|
// // assert(k == size && k == l + g); |
|
// |
|
// return left + l - 1; |
|
// } |
|
|
|
void recursiveQuickSort(int list[], unsigned int left, unsigned int right) |
|
{ |
|
if (left >= right) { |
|
return; |
|
} |
|
|
|
// Partition the subarray list[left ... right] so that |
|
// list[left ... j-1] <= list[j] <= list[j+1 ... right] |
|
unsigned int pivot = partition(list, left, right); // Index of the pivot item. |
|
// Since the type of left and right is "unsigned", we need to prevent overflow |
|
// issues that pivot - 1 > pivot or pivot + 1 < pivot by checking pivot's range. |
|
// e.g., if pivot = 0, (signed)pivot - 1 = -1 = (unsigned)0xFF..F |
|
// = max value of a unsigned int! |
|
recursiveQuickSort(list, left, (pivot == left) ? left : pivot - 1); |
|
recursiveQuickSort(list, (pivot == right) ? right : pivot + 1, right); |
|
|
|
// We could just use the following code if left and right both are |
|
// const (signed) int: |
|
// if (left >= right) { |
|
// return; |
|
// } |
|
// |
|
// int pivot = partition(list, left, right); // Index of the pivot item. |
|
// recursiveQuickSort(list, left, pivot - 1); |
|
// recursiveQuickSort(list, pivot + 1, right); |
|
// It's more easier, but we will lose half of bits of int size to use. |
|
} |
|
|
|
// void iterativeQuickSort(int list[], unsigned int left, unsigned int right) |
|
// { |
|
// std::queue<int> queue; |
|
// queue.push(left); |
|
// queue.push(right); |
|
// |
|
// while (!queue.empty()) { |
|
// unsigned int l = queue.front(); |
|
// queue.pop(); |
|
// unsigned int r = queue.front(); |
|
// queue.pop(); |
|
// |
|
// int pivot = partition(list, l, r); // Index of the pivot item. |
|
// |
|
// if (l + 1 < pivot) { |
|
// queue.push(l); |
|
// queue.push(pivot - 1); |
|
// } |
|
// if (pivot + 1 < r) { |
|
// queue.push(pivot + 1); |
|
// queue.push(r); |
|
// } |
|
// } |
|
// } |
|
|
|
void iterativeQuickSort(int list[], unsigned int left, unsigned int right) |
|
{ |
|
std::stack<int> stack; |
|
stack.push(left); |
|
stack.push(right); |
|
|
|
while (!stack.empty()) { |
|
unsigned int r = stack.top(); |
|
stack.pop(); |
|
unsigned int l = stack.top(); |
|
stack.pop(); |
|
|
|
int pivot = partition(list, l, r); // Index of the pivot item. |
|
|
|
if (l + 1 < pivot) { |
|
stack.push(l); |
|
stack.push(pivot - 1); |
|
} |
|
|
|
if (pivot + 1 < r) { |
|
stack.push(pivot + 1); |
|
stack.push(r); |
|
} |
|
} |
|
} |
|
|
|
// void iterativeQuickSort(int list[], int left, int right) |
|
// { |
|
// std::stack<int> stack; |
|
// stack.push(left); |
|
// stack.push(right); |
|
// |
|
// while (!stack.empty()) { |
|
// int r = stack.top(); |
|
// stack.pop(); |
|
// int l = stack.top(); |
|
// stack.pop(); |
|
// |
|
// if (r <= l) { |
|
// continue; |
|
// } |
|
// |
|
// int pivot = partition(list, l, r); // Index of the pivot item. |
|
// |
|
// stack.push(pivot + 1); |
|
// stack.push(r); |
|
// |
|
// stack.push(l); |
|
// stack.push(pivot - 1); |
|
// } |
|
// } |
|
|
|
void quickSort(int list[], unsigned int length) |
|
{ |
|
assert(length); |
|
// recursiveQuickSort(list, 0, length - 1); |
|
iterativeQuickSort(list, 0, length - 1); |
|
} |