1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
#include <iostream>
#include <iomanip>
#include <string>
#include <ctime>
#include <chrono>
#include <type_traits>
#include <algorithm>
#include <cassert>
#include <random>
// print out processor and elapsed milliseconds to execute function fn
template < typename FN, typename... ARGS >
void time_it( const std::string& name, FN fn, ARGS&&... args )
{
using namespace std::chrono ;
// for measuring elapsed time:
// use the high resolution clock if it is monotonic,
// otherwise fall back to the steady clock
using clock = typename std::conditional< high_resolution_clock::is_steady,
high_resolution_clock, steady_clock >::type ;
std::cout << '\n' << name << ":\n-------------\n" ;
const auto wall_clock_start = clock::now() ;
const auto processor_start = std::clock() ;
fn( std::forward<ARGS>(args)... ) ; // call the function
const auto processor_end = std::clock() ;
const auto wall_clock_end = clock::now() ;
// compute and print result
std::cout << std::fixed << std::setprecision(3)
<< "processor: "
<< (processor_end-processor_start) * 1000.0 / CLOCKS_PER_SEC << " millisecs\n"
<< " elapsed: "
<< duration_cast<microseconds>(wall_clock_end-wall_clock_start).count() / 1000.0 << " millisecs\n" ;
}
void std_sort( std::vector<std::size_t>& seq ) { std::sort( seq.begin(), seq.end() ) ; }
void heap_sort( std::vector<std::size_t>& seq )
{
// https://en.cppreference.com/w/cpp/algorithm/make_heap
std::make_heap( seq.begin(), seq.end() ) ;
// https://en.cppreference.com/w/cpp/algorithm/sort_heap
std::sort_heap( seq.begin(), seq.end() ) ;
}
void merge( std::vector<std::size_t>::iterator begin, std::vector<std::size_t>::iterator end )
{
// https://en.cppreference.com/w/cpp/iterator/distance
const auto dist = std::distance( begin, end ) ;
if( dist > 1 )
{
// https://en.cppreference.com/w/cpp/iterator/next
const auto mid = std::next( begin, dist/2 ) ;
merge( begin, mid ) ;
merge( mid, end ) ;
// https://en.cppreference.com/w/cpp/algorithm/inplace_merge
std::inplace_merge( begin, mid, end ) ;
}
}
void merge_sort( std::vector<std::size_t>& seq ) { merge( seq.begin(), seq.end() ) ; }
void selection_sort( std::vector<std::size_t>& seq )
{
const auto end = seq.end() ;
for( auto iter = seq.begin() ; iter != end ; ++iter )
{
// https://en.cppreference.com/w/cpp/algorithm/min_element
// https://en.cppreference.com/w/cpp/algorithm/iter_swap
std::iter_swap( iter, std::min_element( iter, end ) ) ;
}
}
// helper function to time the sort of our vector
template < typename SORT_FN >
void sort_and_time( const std::string& name, SORT_FN sort_fn, const std::vector<std::size_t>& test_data )
{
auto vec = test_data ; // make a copy of the test data
time_it( name, sort_fn, vec ) ; // time the sort of the copy
assert( std::is_sorted( vec.begin(), vec.end() ) ) ; // sanity check
}
int main()
{
const std::size_t N = 32'000 ;
// create a vector of size N, fill it with random numbers
std::vector<std::size_t> test_data(N) ;
std::mt19937 rng( std::random_device{}() ) ;
std::generate( test_data.begin(), test_data.end(), rng ) ;
// print out timings of the three sorts
sort_and_time( "std sort", std_sort, test_data ) ;
sort_and_time( "heap sort", heap_sort, test_data ) ;
sort_and_time( "merge sort", merge_sort, test_data ) ;
sort_and_time( "selection sort", selection_sort, test_data ) ;
}
| |