How it works
Quicksort partitioning into less/equal/greater regions, especially strong on duplicate-heavy input.
Implementation
function quick3WaySort(arr, stats) { const n = arr.length; if (n < 2) { if (n === 1) markSorted(0); return; } const INSERTION_THRESHOLD = 16; const metrics = stats.educational.metrics; const recordMetric = (name, delta = 1) => { metrics[name] = (metrics[name] || 0) + delta; }; metrics.insertionThreshold = INSERTION_THRESHOLD; function swap(i, j) { if (i === j) return; swap(i, j); const value = arr[i]; arr[i] = arr[j]; arr[j] = value; recordMetric('pairSwaps'); } function compareAndSwap(i, j) { compare(i, j); if (arr[i] > arr[j]) swap(i, j); } function insertionSort(lo, hi) { recordMetric('insertionSortCalls'); for (let i = lo + 1; i <= hi; i++) { const value = arr[i]; let j = i; while (j > lo) { compare(j - 1, i); if (arr[j - 1] <= value) break; arr[j] = arr[j - 1]; recordMetric('writeOperations'); write(j, arr[j]); j--; } arr[j] = value; recordMetric('writeOperations'); write(j, value); } } function pivotToFront(lo, hi) { const mid = lo + (hi - lo >> 1); compareAndSwap(lo, mid); compareAndSwap(lo, hi); compareAndSwap(mid, hi); swap(lo, mid); recordMetric('pivotSelections'); } function sort(lo, hi) { while (lo < hi) { if (hi - lo + 1 <= INSERTION_THRESHOLD) { insertionSort(lo, hi); return; } pivotToFront(lo, hi); const pivot = arr[lo]; let i = lo; let j = hi + 1; let p = lo; let q = hi + 1; while (true) { do { i++; if (i > hi) break; compare(i, lo); } while (i <= hi && arr[i] < pivot); do { j--; compare(j, lo); } while (j >= lo && arr[j] > pivot); if (i === j && i <= hi && arr[i] === pivot) { p++; swap(p, i); recordMetric('equalFrontMoves'); } if (i >= j) break; swap(i, j); if (arr[i] === pivot) { p++; swap(p, i); recordMetric('equalFrontMoves'); } if (arr[j] === pivot) { q--; swap(q, j); recordMetric('equalBackMoves'); } } i = j + 1; for (let k = lo; k <= p; k++) { swap(k, j); j--; } for (let k = hi; k >= q; k--) { swap(k, i); i++; } recordMetric('partitionCalls'); checkpoint(Math.min(metrics.partitionCalls, n), n); if (j - lo < hi - i) { if (lo < j) sort(lo, j); lo = i; } else { if (i < hi) sort(i, hi); hi = j; } } } sort(0, n - 1); for (let i = 0; i < n; i++) markSorted(i); checkpoint(n, n); }
def quick3WaySort(arr, stats): def recordMetric(name, ): metrics[name] = ((metrics[name] or 0) + delta) def swap(i, j): if (i == j): return swap(i, j) value = arr[i] arr[i] = arr[j] arr[j] = value recordMetric("pairSwaps") def compareAndSwap(i, j): compare(i, j) if (arr[i] > arr[j]): swap(i, j) def insertionSort(lo, hi): recordMetric("insertionSortCalls") for i in range((lo + 1), (hi + 1)): value = arr[i] j = i while (j > lo): compare((j - 1), i) if (arr[(j - 1)] <= value): break arr[j] = arr[(j - 1)] recordMetric("writeOperations") write(j, arr[j]) j -= 1 arr[j] = value recordMetric("writeOperations") write(j, value) def pivotToFront(lo, hi): mid = (lo + ((hi - lo) >> 1)) compareAndSwap(lo, mid) compareAndSwap(lo, hi) compareAndSwap(mid, hi) swap(lo, mid) recordMetric("pivotSelections") def sort(lo, hi): while (lo < hi): if (((hi - lo) + 1) <= INSERTION_THRESHOLD): insertionSort(lo, hi) return pivotToFront(lo, hi) pivot = arr[lo] i = lo j = (hi + 1) p = lo q = (hi + 1) while True: while True: i += 1 if (i > hi): break compare(i, lo) if not (((i <= hi) and (arr[i] < pivot))): break while True: j -= 1 compare(j, lo) if not (((j >= lo) and (arr[j] > pivot))): break if (((i == j) and (i <= hi)) and (arr[i] == pivot)): p += 1 swap(p, i) recordMetric("equalFrontMoves") if (i >= j): break swap(i, j) if (arr[i] == pivot): p += 1 swap(p, i) recordMetric("equalFrontMoves") if (arr[j] == pivot): q -= 1 swap(q, j) recordMetric("equalBackMoves") i = (j + 1) for k in range(lo, (p + 1)): swap(k, j) j -= 1 for k in range(hi, (q - 1), -1): swap(k, i) i += 1 recordMetric("partitionCalls") checkpoint((metrics.partitionCalls if metrics.partitionCalls <= n else n), n) if ((j - lo) < (hi - i)): if (lo < j): sort(lo, j) lo = i else: if (i < hi): sort(i, hi) hi = j if (n < 2): if (n == 1): markSorted(0) return INSERTION_THRESHOLD = 16 metrics.insertionThreshold = INSERTION_THRESHOLD sort(0, (n - 1)) for i in range(n): markSorted(i) checkpoint(n, n)
#include <vector> #include <algorithm> void recordMetric(int name, int ); void swap(int i, int j); void compareAndSwap(int i, int j); void insertionSort(int lo, int hi); void pivotToFront(int lo, int hi); void sort(int lo, int hi); void recordMetric(int name, int ) { metrics[name] = (((metrics[name]) != 0 ? (metrics[name]) : (0)) + delta); } void swap(int i, int j) { if((i == j)) { return; } swap(i, j); int value = arr[i]; arr[i] = arr[j]; arr[j] = value; recordMetric("pairSwaps"); } void compareAndSwap(int i, int j) { compare(i, j); if((arr[i] > arr[j])) { swap(i, j); } } void insertionSort(int lo, int hi) { recordMetric("insertionSortCalls"); for(int i=(lo + 1); i<(hi + 1); i++) { int value = arr[i]; int j = i; while((j > lo)) { compare((j - 1), i); if((arr[(j - 1)] <= value)) { break; } arr[j] = arr[(j - 1)]; recordMetric("writeOperations"); write(j, arr[j]); j--; } arr[j] = value; recordMetric("writeOperations"); write(j, value); } } void pivotToFront(int lo, int hi) { int mid = (lo + ((hi - lo) >> 1)); compareAndSwap(lo, mid); compareAndSwap(lo, hi); compareAndSwap(mid, hi); swap(lo, mid); recordMetric("pivotSelections"); } void sort(int lo, int hi) { while((lo < hi)) { if((((hi - lo) + 1) <= INSERTION_THRESHOLD)) { insertionSort(lo, hi); return; } pivotToFront(lo, hi); int pivot = arr[lo]; int i = lo; int j = (hi + 1); int p = lo; int q = (hi + 1); while(1) { do { i++; if((i > hi)) { break; } compare(i, lo); } while(((i <= hi) && (arr[i] < pivot))); do { j--; compare(j, lo); } while(((j >= lo) && (arr[j] > pivot))); if((((i == j) && (i <= hi)) && (arr[i] == pivot))) { p++; swap(p, i); recordMetric("equalFrontMoves"); } if((i >= j)) { break; } swap(i, j); if((arr[i] == pivot)) { p++; swap(p, i); recordMetric("equalFrontMoves"); } if((arr[j] == pivot)) { q--; swap(q, j); recordMetric("equalBackMoves"); } } i = (j + 1); for(int k=lo; k<(p + 1); k++) { swap(k, j); j--; } for(int k=hi; k>(q - 1); k--) { swap(k, i); i++; } recordMetric("partitionCalls"); checkpoint(((metrics.partitionCalls) < (n) ? (metrics.partitionCalls) : (n)), n); if(((j - lo) < (hi - i))) { if((lo < j)) { sort(lo, j); } lo = i; } else { if((i < hi)) { sort(i, hi); } hi = j; } } } void sort(std::vector<int>& arr, int n, int& comparisons, int& swaps) { if((n < 2)) { if((n == 1)) { markSorted(0); } return; } int INSERTION_THRESHOLD = 16; int metrics = educational.metrics; metrics.insertionThreshold = INSERTION_THRESHOLD; sort(0, (n - 1)); for(int i=0; i<n; i++) { markSorted(i); } checkpoint(n, n); }
void recordMetric(int name, int ) { metrics[name] = (((metrics[name]) != 0 ? (metrics[name]) : (0)) + delta); } void swap(int i, int j) { if((i == j)) { return; } swap(i, j); int value = arr[i]; arr[i] = arr[j]; arr[j] = value; recordMetric("pairSwaps"); } void compareAndSwap(int i, int j) { compare(i, j); if((arr[i] > arr[j])) { swap(i, j); } } void insertionSort(int lo, int hi) { recordMetric("insertionSortCalls"); for(int i=(lo + 1); i<(hi + 1); i++) { int value = arr[i]; int j = i; while((j > lo)) { compare((j - 1), i); if((arr[(j - 1)] <= value)) { break; } arr[j] = arr[(j - 1)]; recordMetric("writeOperations"); write(j, arr[j]); j--; } arr[j] = value; recordMetric("writeOperations"); write(j, value); } } void pivotToFront(int lo, int hi) { int mid = (lo + ((hi - lo) >> 1)); compareAndSwap(lo, mid); compareAndSwap(lo, hi); compareAndSwap(mid, hi); swap(lo, mid); recordMetric("pivotSelections"); } void sort(int lo, int hi) { while((lo < hi)) { if((((hi - lo) + 1) <= INSERTION_THRESHOLD)) { insertionSort(lo, hi); return; } pivotToFront(lo, hi); int pivot = arr[lo]; int i = lo; int j = (hi + 1); int p = lo; int q = (hi + 1); while(true) { do { i++; if((i > hi)) { break; } compare(i, lo); } while(((i <= hi) && (arr[i] < pivot))); do { j--; compare(j, lo); } while(((j >= lo) && (arr[j] > pivot))); if((((i == j) && (i <= hi)) && (arr[i] == pivot))) { p++; swap(p, i); recordMetric("equalFrontMoves"); } if((i >= j)) { break; } swap(i, j); if((arr[i] == pivot)) { p++; swap(p, i); recordMetric("equalFrontMoves"); } if((arr[j] == pivot)) { q--; swap(q, j); recordMetric("equalBackMoves"); } } i = (j + 1); for(int k=lo; k<(p + 1); k++) { swap(k, j); j--; } for(int k=hi; k>(q - 1); k--) { swap(k, i); i++; } recordMetric("partitionCalls"); checkpoint(Math.Min(metrics.partitionCalls, n), n); if(((j - lo) < (hi - i))) { if((lo < j)) { sort(lo, j); } lo = i; } else { if((i < hi)) { sort(i, hi); } hi = j; } } } public void Sort(int[] arr, int n, dynamic stats) { if((n < 2)) { if((n == 1)) { markSorted(0); } return; } int INSERTION_THRESHOLD = 16; int metrics = stats.educational.metrics; metrics.insertionThreshold = INSERTION_THRESHOLD; sort(0, (n - 1)); for(int i=0; i<n; i++) { markSorted(i); } checkpoint(n, n); }
#include <stdio.h> void recordMetric(int name, int ); void swap(int i, int j); void compareAndSwap(int i, int j); void insertionSort(int lo, int hi); void pivotToFront(int lo, int hi); void sort(int lo, int hi); void recordMetric(int name, int ) { metrics[name] = (((metrics[name]) != 0 ? (metrics[name]) : (0)) + delta); } void swap(int i, int j) { if((i == j)) { return; } swap(i, j); int value = arr[i]; arr[i] = arr[j]; arr[j] = value; recordMetric("pairSwaps"); } void compareAndSwap(int i, int j) { compare(i, j); if((arr[i] > arr[j])) { swap(i, j); } } void insertionSort(int lo, int hi) { recordMetric("insertionSortCalls"); for(int i=(lo + 1); i<(hi + 1); i++) { int value = arr[i]; int j = i; while((j > lo)) { compare((j - 1), i); if((arr[(j - 1)] <= value)) { break; } arr[j] = arr[(j - 1)]; recordMetric("writeOperations"); write(j, arr[j]); j--; } arr[j] = value; recordMetric("writeOperations"); write(j, value); } } void pivotToFront(int lo, int hi) { int mid = (lo + ((hi - lo) >> 1)); compareAndSwap(lo, mid); compareAndSwap(lo, hi); compareAndSwap(mid, hi); swap(lo, mid); recordMetric("pivotSelections"); } void sort(int lo, int hi) { while((lo < hi)) { if((((hi - lo) + 1) <= INSERTION_THRESHOLD)) { insertionSort(lo, hi); return; } pivotToFront(lo, hi); int pivot = arr[lo]; int i = lo; int j = (hi + 1); int p = lo; int q = (hi + 1); while(1) { do { i++; if((i > hi)) { break; } compare(i, lo); } while(((i <= hi) && (arr[i] < pivot))); do { j--; compare(j, lo); } while(((j >= lo) && (arr[j] > pivot))); if((((i == j) && (i <= hi)) && (arr[i] == pivot))) { p++; swap(p, i); recordMetric("equalFrontMoves"); } if((i >= j)) { break; } swap(i, j); if((arr[i] == pivot)) { p++; swap(p, i); recordMetric("equalFrontMoves"); } if((arr[j] == pivot)) { q--; swap(q, j); recordMetric("equalBackMoves"); } } i = (j + 1); for(int k=lo; k<(p + 1); k++) { swap(k, j); j--; } for(int k=hi; k>(q - 1); k--) { swap(k, i); i++; } recordMetric("partitionCalls"); checkpoint(((metrics.partitionCalls) < (n) ? (metrics.partitionCalls) : (n)), n); if(((j - lo) < (hi - i))) { if((lo < j)) { sort(lo, j); } lo = i; } else { if((i < hi)) { sort(i, hi); } hi = j; } } } void sort(int arr[], int n, int* comparisons, int* swaps) { if((n < 2)) { if((n == 1)) { markSorted(0); } return; } int INSERTION_THRESHOLD = 16; int metrics = (*educational).metrics; metrics.insertionThreshold = INSERTION_THRESHOLD; sort(0, (n - 1)); for(int i=0; i<n; i++) { markSorted(i); } checkpoint(n, n); }