如果方法是常量,如何找到向量的中位数?
how to find the median of a vector if the method is const?
>我创建了一个名为 Collect 的方法,该方法将一堆值添加到向量(如下所示)
void Median::Collect(double datum)
{
myVector.push_back(datum);
}
我需要创建一个方法来计算我在上述方法的向量中收集的所有值的中位数。函数定义写在下面
/* Calculates the median of the data (datum) from the Collect method.
*/
double Median::Calculate() const
{
}
所以我知道我首先需要对向量进行排序才能找到中位数。以下是我的尝试:
double Median::Calculate() const
{
std::sort(myVector.begin(), myVector.end());
double median;
if (myVector.size() % 2 == 0)
{// even
median = (myVector[myVector.size() / 2 - 1] + myVector[myVector.size() / 2]) / 2;
}
else
{// odd
median = myVector[myVector.size() / 2];
}
return median;
}
但我意识到这不是编译,因为该方法是常量,因此对向量的值进行排序会改变向量,这在 const 函数中是不允许的。那么我应该为这种方法做什么呢?
复制myVector
,对其进行排序,然后计算其中位数。
我们可以做得比仅仅使用std::sort
更好一点。我们不需要为了找到中位数而对向量进行完全排序。我们可以使用std::nth_element
来找到中间元素。由于具有偶数个元素的向量的中位数是中间两个元素的平均值,在这种情况下,我们需要做更多的工作来找到另一个中间元素。std::nth_element
确保中间之前的所有元素都小于中间元素。它不能保证它们的顺序超出此范围,因此我们需要使用std::max_element
来查找中间元素之前的最大元素。
您可能没有考虑的另一件事是myVector
为空的情况。找到空向量的中位数实际上没有任何意义。对于此示例,我只是使用了assert
但您可能希望抛出异常或其他内容。
double Median::calculate() const {
assert(!myVector.empty());
std::vector<double> myVectorCopy = myVector;
const auto middleItr = myVectorCopy.begin() + myVectorCopy.size() / 2;
std::nth_element(myVectorCopy.begin(), middleItr, myVectorCopy.end());
if (myVectorCopy.size() % 2 == 0) {
const auto leftMiddleItr = std::max_element(myVectorCopy.begin(), middleItr);
return (*leftMiddleItr + *middleItr) / 2.0;
} else {
return *middleItr;
}
}
另一种选择是使用不同的容器来确保元素始终排序。您可以考虑使用std::set
。当你插入到std::set
时,集合保持排序,所以不必使用std::sort
、std::nth_element
或std::max_element
来查找中位数。你会得到中间元素。
const
方法是一种只能在它所属类的const
实例上调用的方法。 因此,如果您已经声明了一个类Median
并且在其上声明了一个const
方法,则只能使用Median
类的const
实例调用它。不可能影响不同的阶级,就像std::vector
一样。
无论如何,如果您决定从std::vector
派生一个新类并考虑向其添加median
计算中位数的方法,则最好将其声明为const
。这样做的原因是你不需要修改数组来获得它的中位数(见下文)。
如果您需要对数组进行排序,则可以复制,或者更好的是,考虑使用指向数组元素的指针数组,然后根据指向的值对该数组进行排序,然后考虑该数组的中心元素。 这样,您就不会接触原始实例,仍然可以维护该方法的const
属性。
您可以将myVector
声明为mutable
。这将允许数据在其中更改,即使您处于const
函数中也是如此。
如果由于某种原因,这不是一个选项,您可以考虑使用某种数据类型来保持数据排序并将新数据插入正确的位置。然后,您不需要在每次运行此功能时对其进行排序,但会减慢插入速度。考虑一下将更频繁地发生什么:插入或获取中位数。
更难的方法是两全其美。您的向量将保持不变,并且相同函数的第二次运行实际上会比第一次更快地返回答案。
然后,您可以执行以下操作:
// Median.hpp
class Median
{
std::vector<double> myVector;
mutable double median;
mutable bool medianCalculated;
// the rest is the same
};
// Median.cpp
double Median::calculate() const
{
if(!medianCalculated)
{
std::vector<double> copyVector = myVector;
std::sort(copyVector.begin(), copyVector.end();
const auto m1 = copyVector.begin() + (copyVector.size() / 2);
const auto m2 = copyVector.begin() + ((copyVector.size() + 1) / 2);
median = (*m1 + m2) / 2; // m1==m2 for even sized vector m1+1==m2 for odd sized
medianCalculated=true;
}
return median;
}
void Median::Collect(double datum)
{
myVector.push_back(datum);
medianCalculated=false;
}
- 将值指定给向量(2D)的向量中的某个位置
- 计算排序向量的向量中唯一值的计数
- 在C++中调整向量中的索引
- C++:如何循环通过向量中的整数元素
- 为什么我不能将一个对象push_back到属于另一个类的对象向量中?
- 我在二维向量中是否正确分配了内存
- 在 2D 向量中使用第三个 [ ] 有什么意义?
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 如何在C++向量中奇数元素前面加上值-1,我在使用insert函数时遇到了问题
- 添加存储在向量中的大整数的函数出现问题
- 使用迭代器时如何访问对象在向量中的位置?
- 不允许在向量中添加更多元素
- 在c++中键入向量中的所有值后,得到分段错误(核心转储)
- C++重新引用向量中的值
- 选择和修改嵌套向量中的条目的最佳实践
- 如何从用户那里获取输入并将其存储在向量中?
- 从向量中提取最小值、最大值和中位数的最有效方法是什么
- 如果方法是常量,如何找到向量的中位数?
- 如何跟踪整数变化向量的中位数
- 如何找到向量的统计量?最大值/最小值、模式、中位数、平均值