使用C ++查找向量的中值

时间:2017-03-14 16:46:35

标签: c++

我是一名编程学生,对于我正在研究的项目,我必须做的事情是计算int值向量的中值,并且必须通过传递函数来完成。此外,矢量最初使用C ++随机生成器mt19937随机生成,我已经在我的代码中写下了这个。我要使用sort函数和向量成员函数(例如anyaddCookie来执行此操作。 ,和.begin()

我应该确保找到矢量的中值,然后输出

坚持,下面我已经包含了我的尝试。那我哪里错了?如果您愿意给我一些指导或资源以便朝着正确的方向前进,我将不胜感激。

代码:

.end()

3 个答案:

答案 0 :(得分:7)

中位数由

给出
const auto median_it = len.begin() + len.size() / 2;
std::nth_element(len.begin(), median_it , len.end());
auto median = *median_it;

对于偶数(矢量大小),您需要更精确一些。例如,你可以使用

assert(!len.empty());
if (len.size() % 2 == 0) {
    const auto median_it1 = len.begin() + len.size() / 2 - 1;
    const auto median_it2 = len.begin() + len.size() / 2;

    std::nth_element(len.begin(), median_it1 , len.end());
    const auto e1 = *median_it1;

    std::nth_element(len.begin(), median_it2 , len.end());
    const auto e2 = *median_it2;

    return (e1 + e2) / 2;

} else {
    const auto median_it = len.begin() + len.size() / 2;
    std::nth_element(len.begin(), median_it , len.end());
    return *median_it;
}

当然,我们可以通过许多不同的方式获取元素e1。我们也可以使用max或我们想要的任何东西。但这一行很重要,因为nth_element只能正确放置n元素,其余元素在此元素之前或之后排序,具体取决于它们是大还是小。此范围未排序

此代码保证平均具有线性复杂度,即O(N),因此它比排序渐近更好,即O(N log N)

关于您的代码:

    for (i=0; i<len.size(); i++){
        if (len[i]>len[i+1])

这不起作用,因为您在最后一次不存在的迭代中访问len[len.size()]

答案 1 :(得分:4)

std::sort(len.begin(), len.end());
double median = len[len.size() / 2];

会做到的。如果size()是偶数,您可能需要取中间两个元素的平均值,具体取决于您的要求:

0.5 * (len[len.size() / 2 - 1] + len[len.size() / 2]);

答案 2 :(得分:1)

您应该从简单的测试用例开始向上工作,而不是尝试一次完成所有事情:

#include<vector>

double find_median(std::vector<double> len);

// Return the number of failures - shell interprets 0 as 'success',
// which suits us perfectly.
int main()
{
    return find_median({0, 1, 1, 2}) != 1;
}

这已经失败了您的代码(即使将i修复为无符号类型后),因此您可以开始调试(甚至干燥&#39;调试,在那里您通过纸张跟踪代码;这可能就够了。)

我注意到,对于较小的测试用例,例如{0, 1, 2},我会遇到崩溃,而不仅仅是测试失败,所以还有一些事情需要修复。

让我们将实现替换为基于overseas's answer的实现:

#include <algorithm>
#include <limits>
#include <vector>

double find_median(std::vector<double> len)
{
    if (len.size() < 1)
        return std::numeric_limits<double>::signaling_NaN();

    const auto alpha = len.begin();
    const auto omega = len.end();

    // Find the two middle positions (they will be the same if size is odd)
    const auto i1 = alpha + (len.size()-1) / 2;
    const auto i2 = alpha + len.size() / 2;

    // Partial sort to place the correct elements at those indexes (it's okay to modify the vector,
    // as we've been given a copy; otherwise, we could use std::partial_sort_copy to populate a
    // temporary vector).
    std::nth_element(alpha, i1, omega);
    std::nth_element(i1, i2, omega);

    return 0.5 * (*i1 + *i2);
}

现在,我们的测试通过。我们可以编写一个帮助方法来允许我们创建更多的测试:

#include <iostream>
bool test_median(const std::vector<double>& v, double expected)
{
    auto actual = find_median(v);
    if (abs(expected - actual) > 0.01) {
        std::cerr << actual << " - expected " << expected << std::endl;
        return true;
    } else {
        std::cout << actual << std::endl;
        return false;
    }
}

int main()
{
    return test_median({0, 1, 1, 2}, 1)
        +  test_median({5}, 5)
        +  test_median({5, 5, 5, 0, 0, 0, 1, 2}, 1.5);
}

一旦您使用简单的测试用例,您就可以管理更复杂的测试用例。只有这样才能创建大量随机值以查看它的扩展程度:

#include <ctime>
#include <functional>
#include <random>

int main(int argc, char **argv)
{
    std::vector<double> foo;

    const int n = argc > 1 ? std::stoi(argv[1]) : 10;
    foo.reserve(n);

    std::mt19937 rand_generator(std::time(0));
    std::uniform_real_distribution<double> rand_distribution(0,0.8);
    std::generate_n(std::back_inserter(foo), n, std::bind(rand_distribution, rand_generator));

    std::cout << "Vector:";
    for (auto v: foo)
        std::cout << ' ' << v;

    std::cout << "\nMedian = " << find_median(foo) << std::endl;
}

(我已将元素的数量作为命令行参数;在我的构建中比从cin读取它更方便)。请注意,除了在向量中分配 n双倍,我们只需保留容量,但不要创建任何直到需要。

为了好玩和踢,我们现在可以find_median()通用。我会把它留作练习;我建议你从:

开始
typename<class Iterator>
auto find_median(Iterator alpha, Iterator omega)
{
    using value_type = typename Iterator::value_type;

    if (alpha == omega)
        return std::numeric_limits<value_type>::signaling_NaN();
}