#ifndef ROUTING_KIT_SORT_H
#define ROUTING_KIT_SORT_H
#include <routingkit/permutation.h>
#include <vector>
#include <assert.h>
#include <algorithm>
#include <functional>
namespace RoutingKit{
template<class T, class C>
std::vector<unsigned> compute_stable_sort_permutation_using_comparator(const std::vector<T>&v, const C&is_less){
std::vector<unsigned>p = identity_permutation(v.size());
std::stable_sort(
p.begin(), p.end(),
[&](unsigned l, unsigned r){
return is_less(v[l], v[r]);
}
);
return p; }
template<class T, class C>
std::vector<T>stable_sort_using_comparator(const std::vector<T>&v, const C&is_less){
std::vector<T>r = v;
std::stable_sort(r.begin(), r.end(), is_less);
return r; }
template<class T, class C>
std::vector<T>stable_sort_using_comparator(std::vector<T>&&v, const C&is_less){
std::stable_sort(v.begin(), v.end(), is_less);
return std::move(v); }
template<class T, class C>
std::vector<unsigned> compute_sort_permutation_using_comparator(const std::vector<T>&v, const C&is_less){
std::vector<unsigned>p = identity_permutation(v.size());
std::sort(
p.begin(), p.end(),
[&](unsigned l, unsigned r){
return is_less(v[l], v[r]);
}
);
return p; }
template<class T, class C>
std::vector<T>sort_using_comparator(const std::vector<T>&v, const C&is_less){
std::vector<T>r = v;
std::sort(r.begin(), r.end(), is_less);
return r; }
template<class T, class C>
std::vector<T>sort_using_comparator(std::vector<T>&&v, const C&is_less){
std::sort(v.begin(), v.end(), is_less);
return std::move(v); }
template<class T, class C>
bool is_sorted_using_comparator(const std::vector<T>&v, const C&is_less){
for(unsigned i=1; i<v.size(); ++i)
if(is_less(v[i], v[i-1]))
return false;
return true;
}
template<class T, class C>
std::vector<unsigned> compute_inverse_sort_permutation_using_comparator(const std::vector<T>&v, const C&is_less){
return invert_permutation(compute_sort_permutation_using_comparator(v, is_less));
}
template<class T, class C>
std::vector<unsigned> compute_inverse_stable_sort_permutation_using_comparator(const std::vector<T>&v, const C&is_less){
return invert_permutation(compute_stable_sort_permutation_using_comparator(v, is_less));
}
namespace detail{
const unsigned bucket_sort_min_key_to_element_ratio = 16;
template<class T, class K>
std::vector<unsigned>compute_key_pos(const std::vector<T>&v, unsigned key_count, const K&get_key){
std::vector<unsigned>key_pos(key_count, 0);
for(unsigned i=0; i<v.size(); ++i){
unsigned k = get_key(v[i]);
assert(k <= key_count && "key is too large");
++key_pos[k];
}
unsigned sum = 0;
for(unsigned i=0; i<key_count; ++i){
unsigned tmp = sum + key_pos[i];
key_pos[i] = sum;
sum = tmp;
}
return key_pos; }
template<class K>
struct CompareByKey{
explicit CompareByKey(unsigned n, const K&k):get_key(k){
#ifndef NDEBUG
key_count = n;
#else
(void)n;
#endif
}
template<class T>
bool operator()(const T&l, const T&r)const{
unsigned l_key = get_key(l);
assert(l_key < key_count);
unsigned r_key = get_key(r);
assert(r_key < key_count);
return l_key < r_key;
}
#ifndef NDEBUG
unsigned key_count;
#endif
const K&get_key;
};
template<class K>
CompareByKey<K> make_compare_by_key(unsigned n, const K&k){
return CompareByKey<K>(n, k);
}
}
namespace detail{
template<bool is_stable, class T, class K>
std::vector<unsigned> compute_maybe_stable_sort_permutation_using_key(const std::vector<T>&v, unsigned key_count, const K&get_key){
std::vector<unsigned>p;
if(v.size() >= key_count / bucket_sort_min_key_to_element_ratio){
p.resize(v.size());
std::vector<unsigned>key_pos = detail::compute_key_pos(v, key_count, get_key);
for(unsigned i=0; i<v.size(); ++i){
unsigned k = get_key(v[i]);
assert(k <= key_count && "key is too large");
p[key_pos[k]] = i;
++key_pos[k];
}
}else if(is_stable){
p = compute_stable_sort_permutation_using_comparator(v, detail::make_compare_by_key(key_count, get_key));
}else{
p = compute_sort_permutation_using_comparator(v, detail::make_compare_by_key(key_count, get_key));
}
return p; }
}
template<class T, class K>
std::vector<unsigned> compute_sort_permutation_using_key(const std::vector<T>&v, unsigned key_count, const K&get_key){
return detail::compute_maybe_stable_sort_permutation_using_key<false>(v, key_count, get_key);
}
template<class T, class K>
std::vector<unsigned> compute_stable_sort_permutation_using_key(const std::vector<T>&v, unsigned key_count, const K&get_key){
return detail::compute_maybe_stable_sort_permutation_using_key<true>(v, key_count, get_key);
}
namespace detail{
template<bool is_stable, class T, class K>
std::vector<unsigned> compute_inverse_maybe_stable_sort_permutation_using_key(const std::vector<T>&v, unsigned key_count, const K&get_key){
std::vector<unsigned>p;
if(v.size() >= key_count / bucket_sort_min_key_to_element_ratio){
p.resize(v.size());
std::vector<unsigned>key_pos = detail::compute_key_pos(v, key_count, get_key);
for(unsigned i=0; i<v.size(); ++i){
unsigned k = get_key(v[i]);
assert(k <= key_count && "key is too large");
p[i] = key_pos[k];
++key_pos[k];
}
} else if(is_stable){
p = compute_inverse_stable_sort_permutation_using_comparator(v, detail::make_compare_by_key(key_count, get_key));
}else{
p = compute_inverse_sort_permutation_using_comparator(v, detail::make_compare_by_key(key_count, get_key));
}
return p; }
}
template<class T, class K>
std::vector<unsigned> compute_inverse_sort_permutation_using_key(const std::vector<T>&v, unsigned key_count, const K&get_key){
return detail::compute_inverse_maybe_stable_sort_permutation_using_key<false>(v, key_count, get_key);
}
template<class T, class K>
std::vector<unsigned> compute_inverse_stable_sort_permutation_using_key(const std::vector<T>&v, unsigned key_count, const K&get_key){
return detail::compute_inverse_maybe_stable_sort_permutation_using_key<true>(v, key_count, get_key);
}
namespace detail{
template<bool is_stable, class T, class K>
std::vector<T>maybe_stable_sort_using_key(const std::vector<T>&v, unsigned key_count, const K&get_key){
std::vector<T>r;
if(v.size() >= key_count / bucket_sort_min_key_to_element_ratio){
std::vector<unsigned>key_pos = detail::compute_key_pos(v, key_count, get_key);
r.resize(v.size());
for(unsigned i=0; i<v.size(); ++i){
unsigned k = get_key(v[i]);
assert(k <= key_count && "key is too large");
r[key_pos[k]] = v[i];
++key_pos[k];
}
} else if(is_stable) {
r = stable_sort_using_comparator(v, detail::make_compare_by_key(key_count, get_key));
} else {
r = sort_using_comparator(v, detail::make_compare_by_key(key_count, get_key));
}
return r; }
template<bool is_stable, class T, class K>
std::vector<T>maybe_stable_sort_using_key(std::vector<T>&&v, unsigned key_count, const K&get_key){
std::vector<T>r;
if(v.size() >= key_count / bucket_sort_min_key_to_element_ratio){
std::vector<unsigned>key_pos = detail::compute_key_pos(v, key_count, get_key);
r.resize(v.size());
for(unsigned i=0; i<v.size(); ++i){
unsigned k = get_key(v[i]);
assert(k <= key_count && "key is too large");
r[key_pos[k]] = std::move(v[i]);
++key_pos[k];
}
} else if(is_stable) {
r = stable_sort_using_comparator(v, detail::make_compare_by_key(key_count, get_key));
} else {
r = sort_using_comparator(v, detail::make_compare_by_key(key_count, get_key));
}
return r; }
}
template<class T, class K>
std::vector<T>sort_using_key(const std::vector<T>&v, unsigned key_count, const K&get_key){
return detail::maybe_stable_sort_using_key<false>(v, key_count, get_key); }
template<class T, class K>
std::vector<T>sort_using_key(std::vector<T>&&v, unsigned key_count, const K&get_key){
return detail::maybe_stable_sort_using_key<false>(std::move(v), key_count, get_key); }
template<class T, class K>
std::vector<T>stable_sort_using_key(const std::vector<T>&v, unsigned key_count, const K&get_key){
return detail::maybe_stable_sort_using_key<true>(v, key_count, get_key); }
template<class T, class K>
std::vector<T>stable_sort_using_key(std::vector<T>&&v, unsigned key_count, const K&get_key){
return detail::maybe_stable_sort_using_key<true>(std::move(v), key_count, get_key); }
template<class T, class K>
bool is_sorted_using_key(const std::vector<T>&v, unsigned key_count, const K&get_key){
for(unsigned i=1; i<v.size(); ++i)
if(get_key(v[i]) < get_key(v[i-1]))
return false;
return true;
}
template<class T>
std::vector<unsigned> compute_sort_permutation_using_less(const std::vector<T>&v){
return compute_sort_permutation_using_comparator(v, [](const T&l, const T&r){return l < r;});
}
template<class T>
std::vector<unsigned> compute_stable_sort_permutation_using_less(const std::vector<T>&v){
return compute_stable_sort_permutation_using_comparator(v, [](const T&l, const T&r){return l < r;});
}
template<class T>
std::vector<unsigned> compute_inverse_sort_permutation_using_less(const std::vector<T>&v){
return invert_permutation(compute_sort_permutation_using_less(v));
}
template<class T>
std::vector<unsigned> compute_inverse_stable_sort_permutation_using_less(const std::vector<T>&v){
return invert_permutation(compute_stable_sort_permutation_using_less(v));
}
template<class T>
std::vector<T>stable_sort_using_less(const std::vector<T>&v){
return stable_sort_using_comparator(v, [](const T&l, const T&r){return l < r;});
}
template<class T>
std::vector<T>stable_sort_using_less(std::vector<T>&&v){
return stable_sort_using_comparator(std::move(v), [](const T&l, const T&r){return l < r;});
}
template<class T>
std::vector<T>sort_using_less(const std::vector<T>&v){
return sort_using_comparator(v, [](const T&l, const T&r){return l < r;});
}
template<class T>
std::vector<T>sort_using_less(std::vector<T>&&v){
return sort_using_comparator(std::move(v), [](const T&l, const T&r){return l < r;});
}
template<class T>
bool is_sorted_using_less(const std::vector<T>&v){
return is_sorted_using_comparator(v, [](const T&l, const T&r){return l < r;});
}
}
#endif