Нахождение какой строки в массиве имеет наибольшую среднюю температуру - PullRequest
0 голосов
/ 09 ноября 2018

Мне нужно найти строку в массиве, которая имеет наибольшую среднюю температуру. Существует две основные переменные: одна указывает, сколько дней проводят измерения температуры, а другая указывает, сколько измерений проводилось каждый день. К счастью, в большинстве случаев, которые я пробовал, программа показывает правильный день с наибольшей средней температурой. Тем не менее, в некоторых случаях, таких как следующие, это не работает, и я не могу понять, почему.

Если я вставлю следующие значения:

4 3

8 8 10

12 10 7

14 12 11

11 10 12

Он должен отображать 2, так как это день с наибольшей средней температурой. Однако по какой-то причине вместо этого отображается 0.

Вот код, который я использую:

include <iostream>
using namespace std;

void largestaverage (int array[100][100], int amountDays, int amountMeasurements, int &largest, int &largestDay, int dailyAverage)
{
 largest=array[0][0];
 largestDay=0;
 for(int i=0; i<amountDays; i++)
 {
    dailyAverage=0;
     for(int k=0; k<amountMeasurements; k++)
     {
        dailyAverage+=array[i][k];
        dailyAverage=dailyAverage/amountMeasurements;
        if(dailyAverage>largest)
        {
           largest=array[i][k];
           largestDay=i;
        }
     }
  }
}

int main ()
{
 int array[100][100], amountDays, amountMeasurements, largest, largestDay, dailyAverage=0;
 cin>>amountDays;
 cin>>amountMeasurements;
 for (int i=0; i<amountDays; i++)
 {
     for (int k=0; k<amountMeasurements; k++)
     {
         cin>>array[i][k];
     }
 } 
 largestaverage (array, amountDays, amountMeasurements, largest, largestDay, dailyAverage);
 cout<<largestDay<<endl;
 return 0;
}

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Джон, очевидно, вы немного боретесь с пониманием того, какие значения вам нужно передать в качестве параметров вашей функции и как обрабатывать циклы для получения наибольшего среднесуточного значения на основе ваших данных.

Для начала, единственные параметры, которые необходимо передать в largestaverage(), - это сам массив, и границы, указывающие число days и measurements, взятых для каждого дня. Только из этой информации вы можете вычислить наибольшее среднесуточное значение - но как вернуть это наибольшее среднесуточное значение обратно к main(), чтобы его можно было использовать?

Ключом является выбор значимого return type для вашей функции, чтобы вы могли return необходимую информацию. Поскольку вы проверяете данные, которые вы прочитали в array в main() (не так ли?), Нет необходимости выбирать тип возврата, чтобы указать на успех / неудачу расчета, но выбор void не дает никаких преимуществ на всех, и вам остается передать ссылку.

Хотя это будет работать, есть гораздо более фундаментальный способ обработки возврата - просто return значение до main() нужного типа. Это исключает необходимость проходить largest вообще. Функция всегда может вернуть свой собственный тип. Но какого типа? double делает правильный выбор, так как результат деления sum на число measurements приведет к значению с плавающей точкой - если вы не намерены целочисленное деление произойдет.

Внесение изменений в тип возврата для largestaverage и перестановка циклов таким образом, чтобы sum и avg вычислялись ежедневно и должным образом повторно инициализировались на следующий день, включая <limits> так что вы можете использовать стандартный способ инициализации largest наименьшим значением, доступным для вашего type, вы можете сделать что-то похожее на:

...
#include <limits>   /* for numeric_limits */
...
#define MAXDM 100   /* if you need a constant, #define one (or more) */

/* choose a meaningful return type, and return a value */
double largestaverage (int array[][MAXDM], int days, int msrmts)
{
    /* initialize largest sufficiently small (all vals could be negative) */
    double largest = std::numeric_limits<double>::min();

    for (int i = 0; i < days; i++) {        /* loop over each day */
        int sum = 0;                        /* initialize sum/avg */
        double avg = 0;
        for (int k = 0; k < msrmts; k++)    /* loop over measurements */
            sum += array[i][k];             /* compute sum */
        avg = sum / (double)msrmts;         /* compute avg */
        if (avg > largest)                  /* check against largest */
            largest = avg;
    }
    return largest;                         /* return largest */
}

Переставив main() и добавив необходимые проверки для каждого ввода, вы можете сделать что-то похожее на следующее:

int main (void) {

    int array[MAXDM][MAXDM] = {{0}},    /* declare/initialize variables */
        days, measurements;

    if (!(cin >> days >> measurements)) {   /* VALIDATE read of input */
        cerr << "error: invalid format for days/measurements\n";
        return 1;
    }
    for (int i = 0; i < days; i++)          /* loop over days */
        for (int k = 0; k < measurements; k++)  /* loop over measurements */
            if (!(cin>>array[i][k])) {      /* VALIDATE read of input */
                cerr << "error: invalid format row '" << k + 1 << "'\n";
                return 1;
            }

    /* output results */
    cout << "largest daily avg: " 
        << largestaverage (array, days, measurements) << endl;
}

Если поместить его в краткий пример, то получится:

#include <iostream>
#include <limits>   /* for numeric_limits */

using namespace std;

#define MAXDM 100   /* if you need a constant, #define one (or more) */

/* choose a meaningful return type, and return a value */
double largestaverage (int array[][MAXDM], int days, int msrmts)
{
    /* initialize largest sufficiently small (all vals could be negative) */
    double largest = std::numeric_limits<double>::min();

    for (int i = 0; i < days; i++) {        /* loop over each day */
        int sum = 0;                        /* initialize sum/avg */
        double avg = 0;
        for (int k = 0; k < msrmts; k++)    /* loop over measurements */
            sum += array[i][k];             /* compute sum */
        avg = sum / (double)msrmts;         /* compute avg */
        if (avg > largest)                  /* check against largest */
            largest = avg;
    }
    return largest;                         /* return largest */
}

int main (void) {

    int array[MAXDM][MAXDM] = {{0}},    /* declare/initialize variables */
        days, measurements;

    if (!(cin >> days >> measurements)) {   /* VALIDATE read of input */
        cerr << "error: invalid format for days/measurements\n";
        return 1;
    }
    for (int i = 0; i < days; i++)          /* loop over days */
        for (int k = 0; k < measurements; k++)  /* loop over measurements */
            if (!(cin>>array[i][k])) {      /* VALIDATE read of input */
                cerr << "error: invalid format row '" << k + 1 << "'\n";
                return 1;
            }

    /* output results */
    cout << "largest daily avg: " 
        << largestaverage (array, days, measurements) << endl;
}

Пример ввода

$ cat file
4 3
8 8 10
12 10 7
14 12 11
11 10 12

Пример использования / Вывод

$ ./bin/dailyavg < file
largest daily avg: 12.3333

Наибольшее среднее значение, соответствующее вводу за третий день.

Позволяя C ++ выполнять большую часть работы

Хотя в использовании базовых типов массивов и ручных циклов for в C ++ нет ничего плохого, для всех практических целей ваш код и приведенный выше код - не что иное, как стандартный C, кроме использования cin/cout вместо scanf/printf и используя numeric_limits<double>::min() вместо DBL_MIN.

Причина, по которой у нас есть C ++, состоит в том, чтобы упростить задачу. Вместо int array[100][100] объявления целочисленного массива с автоматической продолжительностью хранения и фиксированными границами 100 массивов 100 int каждый, вы можете вместо этого использовать vector<vector<int>> array; и позволить C ++ обрабатывать границы и управление памятью для вас. Вместо того, чтобы зацикливаться на некоторых фиксированных границах, вы просто используете цикл auto range for (C ++ 11), чтобы зациклить то, что заполнено. (это также устраняет необходимость передавать границы вашей функции, вместо этого просто передайте ссылку на array).

Вместо суммирования внутренних и внешних циклов и вычисления каждого среднесуточного значения вы можете просто циклически повторять ежедневные данные, используя accumulate для суммирования значений каждого дня, а затем просто делить на .size() суточного вектора.

Позволяя C ++ выполнять большую часть работы за вас, уменьшается количество циклов, суммирования и усреднения, необходимых, например,

#include <iostream>
#include <vector>   /* for vector */
#include <numeric>  /* for accumulate */
#include <limits>   /* for numeric_limits */

using namespace std;

/* choose a meaningful return type, and return a value */
double largestaverage (vector<vector<int>>& array)
{
    /* initialize largest sufficiently small (all vals could be negative) */
    double largest = std::numeric_limits<double>::min();

    for (auto day : array) {            /* loop over each day vector */
        double avg = accumulate (day.begin(), day.end(), 0) / 
                    static_cast <double>(day.size()); /* compute avg */
        if (avg > largest)              /* check against largest */
            largest = avg;
    }
    return largest;                     /* return largest */
}

int main (void) {

    vector<vector<int>> array;          /* declare vector of vectors */
    int days, measurements;

    if (!(cin >> days >> measurements)) {   /* VALIDATE read of input */
        cerr << "error: invalid format for days/measurements\n";
        return 1;
    }
    for (int i = 0; i < days; i++) {        /* loop over days */
        vector<int> tmp;
        for (int k = 0; k < measurements; k++) { /* loop over measurements */
            int msrmt;
            if (!(cin >> msrmt)) {      /* VALIDATE read of input */
                cerr << "error: invalid format row '" << k + 1 << "'\n";
                return 1;
            }
            tmp.push_back(msrmt);       /* add msrmt to tmp vector */
        }
        array.push_back(tmp);           /* add tmp vector to array */
    }
    /* output results */
    cout << "largest daily avg: " << largestaverage(array) << endl;
}

(вы могли бы даже устранить необходимость читать первую строку вашего файла данных и просто читать дни как string с getline и создавать цикл stringstream и цикл с >> до int до .push_back())

Оба подхода хороши, первый - просто C, и в этом нет ничего плохого, второй использует некоторые тонкости C ++. Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 09 ноября 2018

Установите наибольшее среднее значение, которое вы видите вместо largest=array[i][k].

if(dailyAverage>largest)
{
   largest=dailyAverage;
   largestDay=i;
}

Также, как упомянуто "@Some programmer dude", лучше всего было бы вычислить среднее значение за пределами цикла.

Edit: Инициализируйте самое большое число до невероятно малого числа, поскольку это, скорее всего, приведет к логической ошибке.

largest=-1000;
...