计算向量中存储的值的中位数 - C++?

发布于 2024-08-18 17:32:21 字数 758 浏览 14 评论 0 原文

我是一名编程学生,对于我正在从事的一个项目,我要做的事情之一就是计算 int 值向量的中值。我将仅使用 STL 中的排序函数和向量成员函数(例如 .begin().end().size)来完成此操作()

我还应该确保找到向量是否具有奇数个值或偶数个值的中位数。

卡住了,下面我包含了我的尝试。那么我哪里出错了?如果您愿意给我一些指示或资源以朝着正确的方向前进,我将不胜感激。

代码:

int CalcMHWScore(const vector<int>& hWScores)
{
     const int DIVISOR = 2;
     double median;
     sort(hWScores.begin(), hWScores.end());
     if ((hWScores.size() % DIVISOR) == 0)
     {
         median = ((hWScores.begin() + hWScores.size()) + (hWScores.begin() + (hWScores.size() + 1))) / DIVISOR);
     }
     else 
     {
       median = ((hWScores.begin() + hWScores.size()) / DIVISOR)
     }

    return median;
}

I'm a programming student, and for a project I'm working on, on of the things I have to do is compute the median value of a vector of int values. I'm to do this using only the sort function from the STL and vector member functions such as .begin(), .end(), and .size().

I'm also supposed to make sure I find the median whether the vector has an odd number of values or an even number of values.

And I'm Stuck, below I have included my attempt. So where am I going wrong? I would appreciate if you would be willing to give me some pointers or resources to get going in the right direction.

Code:

int CalcMHWScore(const vector<int>& hWScores)
{
     const int DIVISOR = 2;
     double median;
     sort(hWScores.begin(), hWScores.end());
     if ((hWScores.size() % DIVISOR) == 0)
     {
         median = ((hWScores.begin() + hWScores.size()) + (hWScores.begin() + (hWScores.size() + 1))) / DIVISOR);
     }
     else 
     {
       median = ((hWScores.begin() + hWScores.size()) / DIVISOR)
     }

    return median;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

想挽留 2024-08-25 17:32:22

不需要对向量进行完全排序:std::nth_element 可以做足够的工作将中位数放在正确的位置。请参阅我对 的回答以这个问题为例。

当然,如果你的老师禁止使用正确的工具来完成这项工作,这也无济于事。

There is no need to completely sort the vector: std::nth_element can do enough work to put the median in the correct position. See my answer to this question for an example.

Of course, that doesn't help if your teacher forbids using the right tool for the job.

提笔落墨 2024-08-25 17:32:22

你正在做一个额外的划分,总体上使它比需要的更复杂一些。此外,当 2 实际上在上下文中更有意义时,无需创建 DIVISOR。

double CalcMHWScore(vector<int> scores)
{
  size_t size = scores.size();

  if (size == 0)
  {
    return 0;  // Undefined, really.
  }
  else
  {
    sort(scores.begin(), scores.end());
    if (size % 2 == 0)
    {
      return (scores[size / 2 - 1] + scores[size / 2]) / 2;
    }
    else 
    {
      return scores[size / 2];
    }
  }
}

You are doing an extra division and overall making it a bit more complex than it needs to be. Also, there's no need to create a DIVISOR when 2 is actually more meaningful in context.

double CalcMHWScore(vector<int> scores)
{
  size_t size = scores.size();

  if (size == 0)
  {
    return 0;  // Undefined, really.
  }
  else
  {
    sort(scores.begin(), scores.end());
    if (size % 2 == 0)
    {
      return (scores[size / 2 - 1] + scores[size / 2]) / 2;
    }
    else 
    {
      return scores[size / 2];
    }
  }
}
寂寞美少年 2024-08-25 17:32:22

接受的答案使用 std::sort ,它所做的工作比我们需要的更多。使用 std::nth_element 的答案无法正确处理偶数大小的情况。


我们可以比仅仅使用 std::sort 做得更好一点。我们不需要对向量进行完全排序来找到中位数。我们可以使用 std::nth_element 来查找中间元素。由于具有偶数个元素的向量的中位数是中间两个元素的平均值,因此在这种情况下我们需要做更多的工作来找到另一个中间元素。 std::nth_element 确保中间前面的所有元素都小于中间。它不能保证它们的顺序超出这个范围,因此我们需要使用 std::max_element 来查找中间元素之前的最大元素。

int CalcMHWScore(std::vector<int> hWScores) {
  assert(!hWScores.empty());
  const auto middleItr = hWScores.begin() + hWScores.size() / 2;
  std::nth_element(hWScores.begin(), middleItr, hWScores.end());
  if (hWScores.size() % 2 == 0) {
    const auto leftMiddleItr = std::max_element(hWScores.begin(), middleItr);
    return (*leftMiddleItr + *middleItr) / 2;
  } else {
    return *middleItr;
  }
}

您可能需要考虑返回 double,因为当向量大小为偶数时,中位数可能是分数。

The accepted answer uses std::sort which does more work than we need it to. The answers that use std::nth_element don't handle the even size case correctly.


We can do a little better than just using std::sort. We don't need to sort the vector completely in order to find the median. We can use std::nth_element to find the middle element. Since the median of a vector with an even number of elements is the average of the middle two, we need to do a little more work to find the other middle element in that case. std::nth_element ensures that all elements preceding the middle are less than the middle. It doesn't guarantee their order beyond that so we need to use std::max_element to find the largest element preceding the middle element.

int CalcMHWScore(std::vector<int> hWScores) {
  assert(!hWScores.empty());
  const auto middleItr = hWScores.begin() + hWScores.size() / 2;
  std::nth_element(hWScores.begin(), middleItr, hWScores.end());
  if (hWScores.size() % 2 == 0) {
    const auto leftMiddleItr = std::max_element(hWScores.begin(), middleItr);
    return (*leftMiddleItr + *middleItr) / 2;
  } else {
    return *middleItr;
  }
}

You might want to consider returning a double because the median may be a fraction when the vector has an even size.

美男兮 2024-08-25 17:32:22
const int DIVISOR = 2;

不要这样做。它只会让你的代码更加复杂。您可能已经阅读过有关不使用幻数的指南,但数字的偶数与奇数是一个基本属性,因此将其抽象出来没有任何好处,但会妨碍可读性。

if ((hWScores.size() % DIVISOR) == 0)
{
    median = ((hWScores.begin() + hWScores.size()) + (hWScores.begin() + (hWScores.size() + 1))) / DIVISOR);

您将一个迭代器带到向量的末尾,使用另一个指向向量末尾的迭代器,将迭代器添加在一起(这不是一个有意义的操作),然后除以结果迭代器(这也没有意义)。这是比较复杂的情况;我将首先解释如何处理奇数大小的向量,并将偶数大小的向量留给您作为练习。

}
else 
{
    median = ((hWScores.begin() + hWScores.size()) / DIVISOR)

同样,您正在划分一个迭代器。相反,您想要做的是将迭代器增加到向量的开头 hWScores.size() / 2 元素:

    median = *(hWScores.begin() + hWScores.size() / 2);

并注意,您必须取消引用迭代器从他们身上获取价值。如果使用索引会更简单:

    median = hWScores[hWScores.size() / 2];
const int DIVISOR = 2;

Don't do this. It just makes your code more convoluted. You've probably read guidelines about not using magic numbers, but evenness vs. oddness of numbers is a fundamental property, so abstracting this out provides no benefit but hampers readability.

if ((hWScores.size() % DIVISOR) == 0)
{
    median = ((hWScores.begin() + hWScores.size()) + (hWScores.begin() + (hWScores.size() + 1))) / DIVISOR);

You're taking an iterator to the end of the vector, taking another iterator that points one past the end of the vector, adding the iterators together (which isn't an operation that makes sense), and then dividing the resulting iterator (which also doesn't make sense). This is the more complicated case; I'll explain what to do for the odd-sized vector first and leave the even-sized case as an exercise for you.

}
else 
{
    median = ((hWScores.begin() + hWScores.size()) / DIVISOR)

Again, you're dividing an iterator. What you instead want to do is to increment an iterator to the beginning of the vector by hWScores.size() / 2 elements:

    median = *(hWScores.begin() + hWScores.size() / 2);

And note that you have to dereference iterators to get values out of them. It'd be more straightforward if you used indices:

    median = hWScores[hWScores.size() / 2];
远昼 2024-08-25 17:32:22

我在下面给出了一个示例程序,该程序与 Max S. 的响应中的程序有些相似。为了帮助OP提高他的知识和理解,我做了一些改变。我已经:

a)将通过常量引用的调用更改为按值调用,因为排序将要更改向量中元素的顺序,(编辑:我刚刚看到罗布·肯尼迪在我准备我的文章时也说过这一点post)

b) 用更合适的向量 >::size_type 替换 size_t (实际上,后者的一个方便的同义词),

c) 将 size/2 保存到中间变量,

d)如果向量为空,则抛出异常,并且

e) 我还引入了条件运算符 (? :)。

实际上,所有这些更正都直接出自 Koenig 和 Moo 所著的《Accelerated C++》第 4 章。

double median(vector<int> vec)
{
        typedef vector<int>::size_type vec_sz;

        vec_sz size = vec.size();
        if (size == 0)
                throw domain_error("median of an empty vector");

        sort(vec.begin(), vec.end());

        vec_sz mid = size/2;

        return size % 2 == 0 ? (vec[mid] + vec[mid-1]) / 2 : vec[mid];
}

I give below a sample program that is somewhat similar to the one in Max S.'s response. To help the OP advance his knowledge and understanding, I have made a number of changes. I have:

a) changed the call by const reference to call by value, since sort is going to want to change the order of the elements in your vector, (EDIT: I just saw that Rob Kennedy also said this while I was preparing my post)

b) replaced size_t with the more appropriate vector<int>::size_type (actually, a convenient synonym of the latter),

c) saved size/2 to an intermediate variable,

d) thrown an exception if the vector is empty, and

e) I have also introduced the conditional operator (? :).

Actually, all of these corrections are straight out of Chapter 4 of "Accelerated C++" by Koenig and Moo.

double median(vector<int> vec)
{
        typedef vector<int>::size_type vec_sz;

        vec_sz size = vec.size();
        if (size == 0)
                throw domain_error("median of an empty vector");

        sort(vec.begin(), vec.end());

        vec_sz mid = size/2;

        return size % 2 == 0 ? (vec[mid] + vec[mid-1]) / 2 : vec[mid];
}
无悔心 2024-08-25 17:32:22

我不太确定您对向量成员函数的用户的限制是什么,但是使用 []at() 进行索引访问将使访问元素更简单

median = hWScores.at(hWScores.size() / 2);

:也可以像您当前正在做的那样使用像 begin() + offset 这样的迭代器,但是您需要首先使用 size()/2 计算正确的偏移量并添加到 begin(),而不是相反。此外,您还需要取消引用结果迭代器以访问此时的实际值:

median = *(hWScores.begin() + hWScores.size()/2)

I'm not exactly sure what your restrictions on the user of member functions of vector are, but index access with [] or at() would make accessing elements simpler:

median = hWScores.at(hWScores.size() / 2);

You can also work with iterators like begin() + offset like you are currently doing, but then you need to first calculate the correct offset with size()/2 and add that to begin(), not the other way around. Also you need to dereference the resulting iterator to access the actual value at that point:

median = *(hWScores.begin() + hWScores.size()/2)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文