Массивы переменной длины допустимы в C, но не в C ++.В C ++ лучше использовать коллекцию vector
, поскольку это позволяет лучше представлять намерение, переменный размер массива без необходимости отдельно поддерживать текущий размер.
Следующая полная программа дает вамбазовая линия для работы, в том числе код тестового жгута:
#include <iostream>
#include <vector>
class RunningValues {
public:
RunningValues(size_t size = 50);
void Add(double val);
double Sum();
double Average();
private:
std::vector<double> dataBuffer;
size_t sizeLimit;
double sum;
};
// Constructor: store limit and zero sum (vector is already empty).
RunningValues::RunningValues(size_t size): sizeLimit(size), sum(0.0) {}
// Add a sample.
void RunningValues::Add(double val) {
// Zero size, disallow adds.
if (sizeLimit == 0) return;
// If we would exceed limit, remove earliest.
if (dataBuffer.size() == sizeLimit) {
sum -= dataBuffer[0];
dataBuffer.erase(dataBuffer.begin());
}
// Add value to end.
sum += val;
dataBuffer.push_back(val);
}
// Get the average (zero if nothing yet added) or sum.
double RunningValues::Average() {
if (dataBuffer.size() == 0) return 0.0;
return sum / dataBuffer.size();
}
double RunningValues::Sum() {
return sum;
}
// Test harness.
int main() {
RunningValues test(10);
std::cout << "Ave = " << test.Average() << ", sum = " << test.Sum() << '\n';
for (int i = 40; i < 50; ++i)
{
test.Add(i);
std:: cout << "Add " << i << ", ave = " << test.Average() << ", sum=" << test.Sum() << '\n';
}
for (int i = 0; i < 20; ++i)
{
int val = rand() % 100;
test.Add(val);
std:: cout << "Add " << val << ", ave = " << test.Average() << ", sum=" << test.Sum() << '\n';
}
}
Примерный прогон, который показывает средние и суммы в различных точках, показан ниже:
Ave = 0, sum = 0
Add 40, ave = 40, sum=40
Add 41, ave = 40.5, sum=81
Add 42, ave = 41, sum=123
Add 43, ave = 41.5, sum=166
Add 44, ave = 42, sum=210
Add 45, ave = 42.5, sum=255
Add 46, ave = 43, sum=301
Add 47, ave = 43.5, sum=348
Add 48, ave = 44, sum=396
Add 49, ave = 44.5, sum=445
Add 83, ave = 48.8, sum=488
Add 86, ave = 53.3, sum=533
Add 77, ave = 56.8, sum=568
Add 15, ave = 54, sum=540
Add 93, ave = 58.9, sum=589
Add 35, ave = 57.9, sum=579
Add 86, ave = 61.9, sum=619
Add 92, ave = 66.4, sum=664
Add 49, ave = 66.5, sum=665
Add 21, ave = 63.7, sum=637
Add 62, ave = 61.6, sum=616
Add 27, ave = 55.7, sum=557
Add 90, ave = 57, sum=570
Add 59, ave = 61.4, sum=614
Add 63, ave = 58.4, sum=584
Add 26, ave = 57.5, sum=575
Add 40, ave = 52.9, sum=529
Add 26, ave = 46.3, sum=463
Add 72, ave = 48.6, sum=486
Add 36, ave = 50.1, sum=501
Есливы бы предпочли решение, которое позволяет избежать vector
(это бит расточительно иметь всю эту дополнительную функциональность, когда вектор переходит от размера 0 к N
и затем остается там), вы можете просто использоватьголый массив в куче в виде циклического буфера.
Код для этого - небольшое изменение (без main
, поскольку оно не изменилось):
#include <iostream>
class RunningValues {
public:
RunningValues(size_t size = 50);
~RunningValues();
void Add(double val);
double Sum();
double Average();
private:
size_t count, next, limit;
double sum, *data;
};
RunningValues::RunningValues(size_t size)
: count(0), next(0), limit(size)
, sum(0.0), data(new double[size]) {}
RunningValues::~RunningValues() {
delete[] data;
}
void RunningValues::Add(double val) {
// Zero size, disallow adds.
if (limit == 0) return;
// If we would exceed limit, remove earliest.
if (count == limit) {
sum -= data[next];
--count;
}
// Add value to end.
data[next] = val;
sum += val;
++count;
next = (next + 1) % limit;
}
// Get the average (zero if nothing yet added) or sum.
double RunningValues::Average() {
if (count == 0) return 0.0;
return sum / count;
}
double RunningValues::Sum() {
return sum;
}
Изменения отОснованное на векторе решение довольно незначительно:
- Конструктор больше не имеет вектора (очевидно).Вместо этого он имеет массив фиксированного размера для использования в качестве кольцевого буфера, а также переменные
count
и next
для управления им. - Теперь вам нужен деструктор для очистки буфера (перед векторомуправлял собой).
- при добавлении элементов теперь используются
count
и next
(а не вектор), чтобы выяснить, как настроить сумму и вести учет соответствующих данных. - В вычислениях среднего теперь используется
count
, а не векторный размер.
Кроме этого, он на самом деле очень похож на приведенный выше векторный код.