/// Podany kod działa niepoprawnie dla pewnych danych. Zmień go tak, żeby działał
/// zawsze. Zastosuj reguły borrow checker'a znane z Rust'a i/lub metody synchronizacji.

#include <iostream>
#include <algorithm>
#include <numeric>
#include <thread>
#include <vector>
#include <cmath>

double median(std::vector<double> &values) {
    auto middle = values.begin() + std::ceil(values.size() / 2);

    // nth_element(first, nth, last) is a partial sorting algorithm that
    // rearranges elements in [first, last) such that:
    //
    // * The element pointed at by nth is changed to whatever element would
    //   occur in that position if [first, last) were sorted.
    //
    // * All of the elements before this new nth element are less than or equal
    //   to the elements after the new nth element.
    std::nth_element(values.begin(), middle, values.end());
    auto size = values.size();
    if ((size < 2) || (size % 2 == 1)) {
        return *middle;
    } else {
        return (*middle + *(middle - 1)) / 2;
    }
}

double mean(const std::vector<double> &values) {
    return std::accumulate(values.begin(), values.end(), 0.) / values.size();
}

std::pair<double, double> mean_and_median(std::vector<double> &values) {
    double x, y;

    std::thread t1([&x, &values]() { x = mean(values); });
    std::thread t2([&y, &values]() { y = median(values); });
    t2.join();
    t1.join();

    return std::make_pair(x, y);
}

int main() {
    std::vector<double> values = {};
    for (auto i = 1e5; i >= 0; --i) {
        values.push_back(i);
    }
    std::cout << mean(values) << std::endl;
    auto mean_median = mean_and_median(values);
    std::cout << mean_median.first << " " << mean_median.second << std::endl;
    return 0;
}
