#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <random>
#include <chrono>
using namespace std;
auto vandenman(const vector<int>& x, const int k) {
auto y = x;
std::nth_element(y.begin(), y.begin() + k, y.end());
const auto kthValue = y[k];
auto idxK = std::find(x.begin(), x.end(), kthValue);
return idxK;
}
template<typename It>
auto miscco(It first, It last, const int k) {
auto cmp_it_values = [](It lt, It rt){ return *lt < *rt;};
vector<It> y;
y.reserve(std::distance(first, last));
for(auto it = first; it != last; ++it){
y.emplace_back(it);
}
std::nth_element(y.begin(), y.begin() + k, y.end(), cmp_it_values);
return y[k];
}
template<typename It>
It min_k(It first, It last, int k){
auto cmp_it_values = [](It lt, It rt){ return *lt < *rt;};
auto max_copy = std::min<long>(k, std::distance(first, last));
auto start_it = first;
std::advance(start_it, max_copy);
k++; // k == 0 has to return smallest one element.
std::vector<It> k_smallest;
k_smallest.reserve(k+1);
for(auto it = first; it != start_it; ++it){
k_smallest.push_back(it);
}
std::sort(k_smallest.begin(), k_smallest.end(), cmp_it_values);
for(auto it = start_it; it != last; ++it){
if(k_smallest.empty() || *it < *k_smallest.back()){
auto insertion_point = std::lower_bound(k_smallest.begin(), k_smallest.end(),
it, cmp_it_values);
k_smallest.insert(insertion_point, it);
if(k_smallest.size() > k){
k_smallest.pop_back(); // Remove the largest value
}
}
}
return k_smallest.back(); // The iterator to the min(k, n) smallest value
}
template<typename It>
It min_k_heap(It first, It last, int k){
k++; // k == 0 has to return smallest one element.
auto cmp_it_values = [](It lt, It rt){ return *lt < *rt;};
auto max_copy = std::min<long>(k, std::distance(first, last));
auto start_it = first;
std::advance(start_it, max_copy);
std::vector<It> k_smallest;
k_smallest.reserve(k+1);
for(auto it = first; it != start_it; ++it){
k_smallest.push_back(it);
}
std::make_heap(k_smallest.begin(), k_smallest.end(), cmp_it_values);
for(auto it = start_it; it != last; ++it){
if(*it < *k_smallest.front()){
k_smallest.push_back(it);
push_heap(k_smallest.begin(), k_smallest.end(), cmp_it_values);
pop_heap(k_smallest.begin(), k_smallest.end(), cmp_it_values);
k_smallest.pop_back();
}
}
return k_smallest.front(); // The iterator to the min(k, n) smallest value
}
int main() {
std::vector<int> v(10000);
std::vector<std::vector<int>::iterator> vPtr;
vPtr.reserve(v.size());
for (auto it = v.begin(); it != v.end(); ++it) {
vPtr.push_back(it);
}
std::iota (std::begin(v), std::end(v), 0);
std::mt19937 g(3);
std::shuffle(v.begin(), v.end(), g);
{
auto start = chrono::steady_clock::now();
auto ans1 = *vandenman(v, 50);
auto time1 = chrono::steady_clock::now() - start;
cout << "Orig " << ans1<< " time: ";
cout << chrono::duration <double, nano> (time1).count() << " ns" << endl;
}
{
auto start = chrono::steady_clock::now();
auto ans1 = *miscco(v.begin(), v.end(), 50);
auto time1 = chrono::steady_clock::now() - start;
cout << "Miscco " << ans1<< " time: ";
cout << chrono::duration <double, nano> (time1).count() << " ns" << endl;
}
{
auto start = chrono::steady_clock::now();
std::nth_element(vPtr.begin(), std::next(vPtr.begin(), 50), vPtr.end(), [](auto lt, auto rt) { return (*lt) < (*rt); });
auto ans1 = **std::next(vPtr.begin(), 50);
auto time1 = chrono::steady_clock::now() - start;
cout << "Miscco orig " << ans1 << " time: ";
cout << chrono::duration <double, nano>(time1).count() << " ns" << endl;
}
{
auto start = chrono::steady_clock::now();
auto ans1 = *min_k(v.begin(), v.end(), 50);
auto time1 = chrono::steady_clock::now() - start;
cout << "Emily Binary insertion " << ans1<< " time: ";
cout << chrono::duration <double, nano> (time1).count() << " ns" << endl;
}
{
auto start = chrono::steady_clock::now();
auto ans1 = *min_k_heap(v.begin(), v.end(), 50);
auto time1 = chrono::steady_clock::now() - start;
cout << "Emily Heap " << ans1<< " time: ";
cout << chrono::duration <double, nano> (time1).count() << " ns" << endl;
}
return 0;
}