我是一名编程学生,对于我正在研究的项目,我必须做的事情是计算int值向量的中值,并且必须通过传递函数来完成。此外,矢量最初使用C ++随机生成器mt19937随机生成,我已经在我的代码中写下了这个。我要使用sort函数和向量成员函数(例如any
,addCookie
来执行此操作。 ,和.begin()
。
我应该确保找到矢量的中值,然后输出
我坚持,下面我已经包含了我的尝试。那我哪里错了?如果您愿意给我一些指导或资源以便朝着正确的方向前进,我将不胜感激。
代码:
.end()
答案 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();
}