#include <iostream>
#include <vector>
template<typename T>
std::vector<T> merge(std::vector<T>& arr1, std::vector<T>& arr2)
{
std::vector<T> merged;
auto iter1 = arr1.begin();
auto iter2 = arr2.begin();
while (iter1 != arr1.end() && iter2 != arr2.end())
{
if (*iter1 < *iter2)
{
merged.emplace_back(*iter1);
iter1++;
}
else
{
merged.emplace_back(*iter2);
iter2++;
}
}
if (iter1 != arr1.end())
{
for (; iter1 != arr1.end(); iter1++)
merged.emplace_back(*iter1);
}
else
{
for (; iter2 != arr2.end(); iter2++)
merged.emplace_back(*iter2);
}
return merged;
}
template<typename T>
std::vector<T> merge_sort(std::vector<T> arr)
{
if (arr.size() > 1)
{
auto mid = size_t(arr.size() / 2);
auto left_half = merge_sort<T>(std::vector<T>(arr.begin(), arr.begin() + mid));
auto right_half = merge_sort<T>(std::vector<T>(arr.begin() + mid, arr.end()));
return merge<T>(left_half, right_half);
}
return arr;
}
int main()
{
std::vector<int> S {45, 1, 3, 1, ...}
auto sorted_S1 = merge_sort<int>(S1);
}
#include <iostream>
#include <vector>
template <typename T>
auto partition(typename std::vector<T>::iterator begin,
typename std::vecotr<T>::iterator end)
{
auto pivot_val = *begin;
auto left_iter = begin + 1;
auto right_iter = end;
while (true)
{
// vector의 첫 원소부터 시작해 pivot보다 큰 원소를 찾는다.
while (*left_iter <= pivot_val && std::distance(left_iter, right_iter) > 0)
left_iter++;
// vector 마지막 우너소부터 시작해서 역순으로 pivot보다 작은 원소를 찾는다.
while (*right_iter > pivot_val && std::distance(left_iter, right_iter) > 0)
right_iter--;
if (left_iter == right_iter)
break; // 교환할 원소가 없음을 의미
else
// left_iter, right_iter가 가리키는 원소를 서로 교환
std::iter_swap(left_iter, right_iter);
}
if (pivot_val > *right_iter)
std::iter_swap(begin, right_iter);
return right_iter;
}
template<typename T>
void quick_sort(typename std::vector<T>::iterator begin,
typename std::vector<T>::iterator last)
{
if (std::distance(begin, last) >= 1)
{
auto partition_iter = partition<T>(begin, last);
quick_sort<T>(begin, partition_iter - 1);
quick_sort<T>(partition_iter, last);
}
}
int main()
{
std::vector<int> S1 {45, 1, 3, 1, ...}
quick_sort<int>(S1.begin(), S1.end() - 1);
return 0;
}
병합
퀵
앞에서 살펴본 분할 정복 알고리즘은 각 단계에서 문제를 정확하게 두 개 부분문제로 나눴다.
그러나 각 단계에서 문제를 두 개 이상으로 분할하는 것이 더 유리한 경우도 있다. 이러한 문제를 다룬 것이 linear time selection이다.
Ex) 밴드퍼레이드
#include <iostream>
#include <vector>
template<typename T>
auto find_median(typename std::vector<T>::iterator begin,
typename std::vector<T>::iterator last)
{
quick_sort<T>(begin, last); // 정렬
return begin + (std::distance(begin, last / 2);
}
template<typename T>
auto partition_using_given_pivot(typename std::vector<T>::iterator begin,
typename std::vector<T>::iterator end,
typename std::vector<T>::iterator pivot)
{
auto left_iter = begin;
auto right_iter = end;
while (true)
{
while (*left_iter < *pivot && left_iter != right_iter)
left_iter++;
while (*right_iter >= *pivot && left_iter != right_iter)
rigth_iter--;
if (left_iter == right_iter)
break;
else
std::iter_swap(left_iter, right_iter);
}
if (*pivot > *right_iter)
std::iter_swap(pivot, right_iter);
return right_iter;
}
template<typename T>
typename std::vector<T>::iterator linear_time_select(
typename std::vector<T>::iterator begin,
typename std::vector<T>::iterator last,
size_t i)
{
auto size = std::distance(begin, last);
if (size > 0 && i < size)
{
auto num_Vi = (size + 4) / 5
std::accumulate()
std::transform()
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cmath>
void tranform_test(std::vector<int> S)
{
std::vector<int> Tr;
std::transform(S.begin(), S.end(), std::back_inserter(Tr),
[](int x) { return std::pow(x, 2.0); });
std::for_each(S.begin(), S.end(), [](int& x) { x = std::pow(x, 2.0); });
}
std::transform()
은 입력 벡터를 바꾸지 않고, 별도의 벡터를 만들어 반환std::for_each()
는 입력 벡터 자체를 변경void reduce_test(std::vector<int> S)
{
auto ans = std::accumulate(S.begin(), S.end(), 0,
[](int acc, intx) { return acc + x});
}
int main()
{
std::vector<int> S {1, 10, 4, 7, 3, ...};
transform_test(S);
reduce_test(S);
}
#include <iostream>
#include "mapreduce.hpp"
namespace prime_calculator {
bool const is_prime(long const number)
{
if (number > 2)
{
if (number % 2 == 0)
return false;
long const n = std::abs(number);
long const sqrt_number = static_cast<long>(std::sqrt(static_cast<double>(n));
for (long i = 3; i <= sqrt_number; i += 2)
{
if (n % i == 0)
return false;
}
}
else if (number == 0 || number == 1)
return false;
return true;
}
template<typename MapTask>
class number_source : mapreduce::detail::noncopyable
{
public:
number_source(long first, long last, long step)
:sequence_(0), first_(first), last_(last, step_(step) {}
bool const setup_key(typename MapTask::key_type& key)
{
key = sequence_++;
return (key * step_ <= last_);
}
bool const get_data(typename MapTask::key_type const& key,
typename MapTask::value_type& value)
{
typename MapTask::value_type val;
val.first = first_ + (key * step_);
val.second = std::min(val.first + step_ - 1, last_);
std::swap(val, value);
return true;
}
private:
long sequence_;
long const step_;
long const last_;
long const first_;
};
struct map_task : public mapreduce::map_task<long, std::pair<long, long>>
{
template<typename Runtime>
void operator()(Runtime& runtime, key_type const& /*key*/, value_type const& value) const
{
for (key_type loop = value.first; loop <= value.second; ++loop)
runtime.emit_intermediate(is_prime(loop), loop);
}
};
struct reduce_task : public mapreduce::reduce_task<bool, long>
{
template<typename Runtime, typename It>
void operator()(Runtime& runtime, key_type const& key, It, it, It, ite) const
{
if (key)
std::for_each(it, ite, std::bind(&Runtime::emit, &runtime, true, std::placeholders::_1));
}
};
typedef mapreduce::job<prime_calculator::map_task,
prime_calculator::reduce_task,
mapreduce::null_combiner,
prime_calculator::number_source<prime_calculator::map_task>> job;
}