Interstellar12312

Modified Pivot Median vs Standard Pivot Median Quicksort

Mar 16th, 2026
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.26 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <random>
  5. #include <chrono>
  6.  
  7. // Modified Pivot Median vs Standard Pivot Median Quicksort
  8. // Contact Email [email protected]
  9. // Created by I.A
  10.  
  11. const int NUM_ELEMENTS = 1000000; // 1000000-100000000
  12. const int NUM_TRIALS = 1000;        // Number of test runs to average
  13.  
  14. thread_local std::random_device rd_pivot;
  15. thread_local std::mt19937 gen_pivot(rd_pivot());
  16.  
  17. // Standard Hoare Partition using a pre-selected pivot value
  18. int partition(std::vector<int>& arr, int low, int high, int pivot) {
  19.     int i = low - 1;
  20.     int j = high + 1;
  21.  
  22.     while (true) {
  23.         do { i++; } while (arr[i] < pivot);
  24.         do { j--; } while (arr[j] > pivot);
  25.  
  26.         if (i >= j) return j;
  27.         std::swap(arr[i], arr[j]);
  28.     }
  29. }
  30.  
  31. int getStandardMedian(const std::vector<int>& arr, int low, int high) {
  32.     int mid = low + (high - low) / 2;
  33.     int a = arr[low], b = arr[mid], c = arr[high];
  34.  
  35.     int max_v = std::max({a, b, c});
  36.     int min_v = std::min({a, b, c});
  37.     return a + b + c - max_v - min_v;
  38. }
  39.  
  40. void standardQuicksort(std::vector<int>& arr, int low, int high) {
  41.     if (low < high) {
  42.         int pivot = getStandardMedian(arr, low, high);
  43.         int p = partition(arr, low, high, pivot);
  44.  
  45.         standardQuicksort(arr, low, p);
  46.         standardQuicksort(arr, p + 1, high);
  47.     }
  48. }
  49.  
  50.  
  51. // Modified Median
  52.  
  53. int getCustomMedian(const std::vector<int>& arr, int low, int high) {
  54.     int mid = low + (high - low) / 2;
  55.     int a = arr[low], b = arr[mid], c = arr[high];
  56.  
  57.     int max_val = std::max({a, b, c});
  58.     int min_val = std::min({a, b, c});
  59.     int med_val = a + b + c - max_val - min_val;
  60.  
  61.     double total_range = (double)max_val - min_val;
  62.  
  63.     // Prevent division by zero if all three numbers are identical
  64.     if (total_range <= 0.0) return med_val;
  65.  
  66.     // 1. Calculate gaps and their percentage of the total range
  67.     double gap_min = med_val - min_val;
  68.     double gap_max = max_val - med_val;
  69.  
  70.     double pct_min = gap_min / total_range;
  71.     double pct_max = gap_max / total_range;
  72.  
  73.     // 2. If the median is relatively centered, do nothing.
  74.     // Below are notes for different percentages and tests
  75.     // We use a 75% threshold. If one gap takes up more than 75% of the total range,
  76.     // the other number is a massive outlier.
  77.     // [1, 5000, 10000] -> pct_max is ~50% (Passed, returns 5000)
  78.     // [1, 5000, 40000] -> pct_max is ~87.5% (Triggers the fallback below)
  79.     if (pct_max <= 0.75 && pct_min <= 0.75) {
  80.         return med_val;
  81.     }
  82.  
  83.     // 3. Random Search Fallback
  84.     int max_attempts = 5;
  85.  
  86.     for (int i = 0; i < max_attempts; ++i) {
  87.         // Pick a random number from the current sub-array
  88.         int rand_idx = low + std::rand() % (high - low + 1);
  89.         int candidate = arr[rand_idx];
  90.  
  91.         if (pct_max > 0.80) {
  92.             // Max is the outlier. Target the gap between med and max.
  93.             double margin = gap_max * 0.80;
  94.             if (candidate >= med_val + margin && candidate <= max_val - margin) {
  95.                 return candidate;
  96.             }
  97.         }
  98.         else if (pct_min > 0.80) {
  99.             // Min is the outlier. Target the gap between min and med.
  100.             double margin = gap_min * 0.80;
  101.             if (candidate >= min_val + margin && candidate <= med_val - margin) {
  102.                 return candidate;
  103.             }
  104.         }
  105.     }
  106.     // just return the original median so QuickSort doesn't crash.
  107.     return med_val;
  108. }
  109.  
  110. void customQuicksort(std::vector<int>& arr, int low, int high) {
  111.     if (low < high) {
  112.         int pivot = getCustomMedian(arr, low, high);
  113.         int p = partition(arr, low, high, pivot);
  114.  
  115.         customQuicksort(arr, low, p);
  116.         customQuicksort(arr, p + 1, high);
  117.     }
  118. }
  119.  
  120. int main() {
  121.     std::cout << "Starting Quicksort Benchmark..." << std::endl;
  122.     std::cout << "Elements: " << NUM_ELEMENTS << " | Trials: " << NUM_TRIALS << "\n" << std::endl;
  123.  
  124.     std::random_device rd;
  125.     std::mt19937 gen(rd());
  126.     std::uniform_int_distribution<> distrib(1, 100);
  127.  
  128.     std::vector<int> source_data(NUM_ELEMENTS);
  129.     std::chrono::duration<double> total_std_time(0);
  130.     std::chrono::duration<double> total_cust_time(0);
  131.  
  132.     for (int t = 1; t <= NUM_TRIALS; ++t) {
  133.         // 1. Generate fresh random data for this trial
  134.         for (int i = 0; i < NUM_ELEMENTS; ++i) {
  135.             source_data[i] = distrib(gen);
  136.         }
  137.  
  138.         // --- Benchmark Standard ---
  139.         std::vector<int> data_std = source_data;
  140.         auto start_std = std::chrono::steady_clock::now();
  141.         standardQuicksort(data_std, 0, NUM_ELEMENTS - 1);
  142.         auto end_std = std::chrono::steady_clock::now();
  143.         total_std_time += (end_std - start_std);
  144.  
  145.         // --- Benchmark Custom ---
  146.         std::vector<int> data_cust = source_data;
  147.         auto start_cust = std::chrono::steady_clock::now();
  148.         customQuicksort(data_cust, 0, NUM_ELEMENTS - 1);
  149.         auto end_cust = std::chrono::steady_clock::now();
  150.         total_cust_time += (end_cust - start_cust);
  151.  
  152.         // Sanity check on first trial
  153.         if (t == 1) {
  154.             if (!std::is_sorted(data_std.begin(), data_std.end()) ||
  155.                 !std::is_sorted(data_cust.begin(), data_cust.end())) {
  156.                 std::cerr << "Sorting Error Detected!" << std::endl;
  157.                 return 1;
  158.             }
  159.         }
  160.  
  161.         if (t % 100 == 0) {
  162.             std::cout << "Completed Trial " << t << "/" << NUM_TRIALS << "\r" << std::flush;
  163.         }
  164.     }
  165.  
  166.     std::cout << "\n\n--- BENCHMARK RESULTS ---" << std::endl;
  167.     std::cout << "Standard Median-of-Three Avg: " << total_std_time.count() / NUM_TRIALS << " seconds" << std::endl;
  168.     std::cout << "Modified Custom Pivot Avg:   " << total_cust_time.count() / NUM_TRIALS << " seconds" << std::endl;
  169.  
  170.     if (total_cust_time < total_std_time) {
  171.         double diff = (total_std_time.count() - total_cust_time.count()) / total_std_time.count() * 100.0;
  172.         std::cout << "\nCustom logic was " << diff << "% faster." << std::endl;
  173.     } else {
  174.         double diff = (total_cust_time.count() - total_std_time.count()) / total_std_time.count() * 100.0;
  175.         std::cout << "\nStandard logic was " << diff << "% faster." << std::endl;
  176.     }
  177.  
  178.     return 0;
  179. }
Advertisement
Add Comment
Please, Sign In to add comment