Стандартно отклоненный FibonacciLinkedList с помощью Node implementationMemory с твист-областью CursorAdapter Framework DesignEntity с репозиторием и шаблоном Unit of Work и архитектурой POCO Рекурсивная реализация shared_mutexСортирование большого 1GB-файла с 100-миллионным числом с использованием сортировки слияния. Эти if-утверждения слишком причудливы? Случайный IP-адрес GeneratorPI Calculator, Interview ChallengeGenerating Even Random NumbersChecking, если число делится на 9Password validation в JavaCounting строк в CSV-файле, которые соответствуют строке базы данных, каждая из которых имеет миллион записей. Когда «Актовый вопрос» слишком тонкий. Алгоритм командной строки в мини-программе «Полупроводник». IEnumerable & л; Т > должны ToList () или notAdvanced и Подробные вероятности мин.

Я новичок в C ++ (около 4 недель без опыта программирования на других языках), и я пишу программу , чтобы сделать следующее:

  • Определить массив из 100 последовательных номеров типа float.
  • Определите массив из 20 чисел Фибоначчи типа int.
  • Используйте перегруженную функцию для вычисления среднего массива, содержащего 100 чисел.
  • Используйте перегруженную функцию для вычисления стандартного отклонения массива, содержащего 100 чисел.
  • Используйте перегруженную функцию для вычисления среднего массива, содержащего 20 чисел Фибоначчи.
  • Используйте перегруженную функцию для вычисления стандартного отклонения массива, содержащего 20 чисел Фибоначчи.

#include "stdafx.h"
#include <iostream>
#include <cmath>
using namespace std;

const int SIZE_OF_GENERIC_ARRAY = 100;
const int SIZE_OF_FIBONACCI_ARRAY = 20;

double arithmeticAverage;
char sequenceType;

float Array[SIZE_OF_GENERIC_ARRAY];
int Fibonacci[SIZE_OF_FIBONACCI_ARRAY];

void fillGenericArray(int SIZE_OF_GENERIC_ARRAY);
void fillFibonacciArray(int SIZE_OF_FIBONACCI_ARRAY);

double mean(float[], int);
double mean(int[], int);

double standardDeviation(float[], int);
double standardDeviation(int[], int);

void outputMean();
void outputStandardDeviation();

int _tmain(int argc, _TCHAR* argv[])
{
   cout << "Would you like to generate a generic sequence or a Fibonacci sequence?"
     << endl
       << "\n"
       << "Type [G] + [ENTER] for a generic sequence, or;" << endl
       << "Type [F] + [ENTER] for a Fibonacci sequence: ";
   cin >> sequenceType;

    if (sequenceType == 'G' || sequenceType == 'g')
   {
       fillGenericArray(SIZE_OF_GENERIC_ARRAY);
       outputMean();
       outputStandardDeviation();
}

   else if (sequenceType == 'F' || sequenceType == 'f')
   {
       fillFibonacciArray(SIZE_OF_FIBONACCI_ARRAY);
       outputMean();
       outputStandardDeviation();
   }

   else
       cout << "\n"
            << "Invalid input. Please type 'F' or 'G'. Thank you.";

   return 0;
}

void fillGenericArray(int SIZE_OF_GENERIC_ARRAY)
{
   int i = 0;

   Array[0] = { 1 };

   for (int i = 0; i < SIZE_OF_GENERIC_ARRAY; i++)
       Array[i] = i + 1;

   return;
}

void fillFibonacciArray(int SIZE_OF_FIBONACCI_ARRAY)
{
   int i;

   Array[0] = { 0 };
   Array[1] = { 1 };

   for (int i = 2; i < SIZE_OF_FIBONACCI_ARRAY; i++)
       Array[i] = Array[i - 1] + Array[i - 2];

   return;
}

double mean(float Array[], int SIZE_OF_GENERIC_ARRAY)
{
   double sumOfElements = 0;
   int i;

   for (i = 0; i < SIZE_OF_GENERIC_ARRAY; i++)
   {
       sumOfElements += Array[i];
   }
   arithmeticAverage = sumOfElements / i;
   return (arithmeticAverage);
}

double mean(int Array[], int SIZE_OF_FIBONACCI_ARRAY)
{
   double sumOfElements = 0;
   int i;

   for (i = 0; i < SIZE_OF_FIBONACCI_ARRAY; i++)
   {
       sumOfElements += Array[i];
   }
   arithmeticAverage = sumOfElements / i;
   return (arithmeticAverage);
}

double standardDeviation(float Array[], int SIZE_OF_GENERIC_ARRAY)
{
   double standardDeviation;
   double tempSum = 0;

   for (int i = 0; i < SIZE_OF_GENERIC_ARRAY; i++)
   {
       tempSum += pow((Array[i] - mean(Array, SIZE_OF_GENERIC_ARRAY)), 2);
   }
   standardDeviation = sqrt(tempSum / (SIZE_OF_GENERIC_ARRAY));
   return (standardDeviation);
}

double standardDeviation(int Array[], int SIZE_OF_FIBONACCI_ARRAY)
{
   double standardDeviation;
   double tempSum = 0;

   for (int i = 0; i < SIZE_OF_FIBONACCI_ARRAY; i++)
   {
       tempSum += pow((Array[i] - mean(Array, SIZE_OF_FIBONACCI_ARRAY)), 2);
   }
   standardDeviation = sqrt(tempSum / (SIZE_OF_FIBONACCI_ARRAY));
   return (standardDeviation);
}

void outputMean()
{
   cout << "\n";
   cout << "The mean is: " << mean(Array, SIZE_OF_GENERIC_ARRAY);
   cout << endl;
}

void outputStandardDeviation()
{
   cout << "\n";
   cout << "The standard deviation is: " << standardDeviation(Array,
    SIZE_OF_GENERIC_ARRAY);
   cout << endl;
}

Этот код компилирует и выводит правильные результаты. Но я чувствую, что написал много кода и имею некоторые сокращения.

Я правильно использую понятие перегрузки? Есть ли лучший способ вызвать функции mean() и standardDeviation() изнутри кода void outputMean() и void outputStandardDeviation() функции? Есть ли способ, которым я могу оптимизировать любое из этого и сделать его более эффективным?

0 голосов | спросил Yechiel LabunskiySimon ForsbergrogerstoneNaorEmily 27 FebruaryEurope/MoscowbThu, 27 Feb 2014 17:43:11 +0400000000pmThu, 27 Feb 2014 17:43:11 +040014 2014, 17:43:11

4 ответа


22

Я нашел пару вещей, которые могли бы помочь вам улучшить ваш код.

Не злоупотребляйте using namespace std

Помещение using namespace std вверху каждой программы плохая привычка , которую вы бы хорошо избежали.

Избегайте использования глобальных переменных

Возможно, имеет смысл иметь SIZE_OF_GENERIC_ARRAY как глобальную переменную, но не arithmeticAverage. Обычно лучше явно передавать переменные, которые вам понадобятся, а не использовать неопределенную неявную связь глобальной переменной.

Пропустить необходимые переменные явно

Это в основном другой способ указания предыдущего элемента. В качестве примера у вас есть функция fillGenericArrray(), которая принимает целочисленный аргумент, который является размером массива. Это хорошо, но также следует принять массив, который будет заполнен в качестве другого аргумента. Полагая это на практике, мы получаем следующее:

void fillGenericArray(float array[], int arraysize)
{
   for (int i = 0; i < arraysize; ++i)
       array[i] = i + 1;
}

Обратите также внимание на то, что инициализация первого элемента уже выполняется внутри цикла и не нужно делать явно.

Используйте шаблон функции для почти идентичных функций

Ваши две версии mean идентичны, за исключением того, что один принимает массив float, а другой - массив int. Вы можете упростить это, используя шаблон:

template<typename T>
double mean(T array[], int arraysize)
{
   double sumOfElements = 0;
   for (int i = 0; i < arraysize; ++i)
       sumOfElements += array[i];
   return sumOfElements / arraysize;
}

Обратите внимание, что я также сделал несколько других изменений.

  • переместил объявление i в цикле
  • изменил имена прошедших переменных
  • устранена локальная переменная arithmeticMean
  • удалены ложные круглые скобки из оператора return
  • переход от постинкремента к преинкрементному для переменной цикла

Предварительные вычисления инвариантов цикла

A loop-инвариант - это значение, используемое в конструкции цикла, которая не изменяется. Сейчас ваш код пересчитывает mean для каждой итерации цикла for в функции standardDeviation. Поскольку он не изменяется, лучше рассчитать его только один раз, а затем использовать его повторно в цикле. Объединяя это с идеями в предыдущей точке, эти две функции становятся этой единственной шаблонной функцией:

template<typename T>
double standardDeviation(T array[], int arraysize)
{
   double tempSum = 0;
   double mymean = mean(array, arraysize);
   for (int i = 0; i < arraysize; ++i)
   {
       tempSum += pow((array[i] - mymean), 2);
   }
   return sqrt(tempSum / arraysize);
}

Устранить неиспользуемые переменные

Этот код объявляет переменную i вверху как fillGenericArray и fillFibonacciArray, но затем переопределяет ее в рамках for в каждом. Вы можете (и должны) исключить избыточное объявление i в верхней части каждой из этих функций. Кроме того, обратите внимание, что ваш компилятор достаточно умен, чтобы помочь вам найти такую ​​проблему, если вы знаете, как ее попросить.

У функций есть только одна вещь

Ваша функция outputMean() выполняет две функции: вычисляет и выводит среднее значение. Лучше было бы сделать что-то вроде этого:

    std::ostream& outputMean(std::ostream &out, double mean)
    {
        return out << "\nThe mean is: " << mean << '\n';
    }

Или, потому что теперь это довольно просто, исключите функциюполностью и назовите его из main() следующим образом:

    std::cout << "\nThe mean is: " << mean(Array, SIZE_OF_GENERIC_ARRAY) << '\n';

Заметьте, что это исключает ошибку в вашем существующем коде - независимо от того, какой выбор сделан, outputMean() и outputStandardDeviation() оба всегда вычисляют значение Array и никогда не относится к Fibonacci.

Не используйте std::endl, когда \n будет делать

Испушение std::endl фактически очищает поток, а также выдаёт символ новой строки. Это требует дополнительного времени и кода, который вам действительно не нужен в вашем коде. Вместо этого просто используйте \n во всех случаях в этом конкретном коде.

Update:

Я заметил, что код использует те же имена для глобальных переменных, локальных переменных и параметров функции. Это путает вещи, и их лучше избегать. Например, ваш код имеет глобальную переменную:

const int SIZE_OF_FIBONACCI_ARRAY = 20;

Затем он используется в main как:

fillFibonacciArray(SIZE_OF_FIBONACCI_ARRAY);

Код для этой функции:

void fillFibonacciArray(int SIZE_OF_FIBONACCI_ARRAY)
{
   int i;

   Array[0] = { 0 };
   Array[1] = { 1 };

   for (int i = 2; i < SIZE_OF_FIBONACCI_ARRAY; i++)
       Array[i] = Array[i - 1] + Array[i - 2];

   return;
}

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

void fillFibonacciArray(int mysize)
{
   int i;

   Array[0] = 0;
   Array[1] = 1;  // note that we don't need braces here

   for (int i = 2; i < mysize; i++)
       Array[i] = Array[i - 1] + Array[i - 2];

   //  we don't need an explicit return at the end of a void function
}

Когда эта функция вызывается как fillFibonacciArray(SIZE_OF_FIBONACCI_ARRAY), формальный параметр mysize заменяется фактическим параметром SIZE_OF_FIBONACCI_ARRAY, который был объявлен глобально со значением 20. Что вводит в заблуждение относительно вашего исходного кода, так это формальный параметр с именем SIZE_OF_FIBONACCI_ARRAY который затем получает действительный параметр , который имеет одно и то же имя. К сожалению, тогда код ссылается на Array, который является глобальной переменной. Эффект заключается в том, что вместо создания серии из значений int из 20 int в массиве Fibonacci ваш код фактически вводит значения 20 float в первом 20 слотов в Array и массив Fibonacci никогда не используются. См. эту статью в Википедии для более полного и более полного объяснения терминов формальный параметр и фактический параметр и что они означают.

ответил Edward 2 J000000Wednesday14 2014, 19:33:23
11

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

using namespace std;

Никогда. std заполняется постоянно растущим числом неограниченных шаблонных алгоритмов с общими именами. Цена написания std::cout вместо cout ничего не значит, и цена наличия компилятора std::distance вместо вашего собственный distance заставит вас плакать.

const int SIZE_OF_GENERIC_ARRAY = 100; 
const int SIZE_OF_FIBONACCI_ARRAY = 20;

Все имена верхнего регистра обычно зарезервированы для макросов. Вы не хотите знать, что произойдет, если вы столкнетесь с макросом. Кроме того, они известны как «размеры магического буфера» - это константы без логики или причины. Вы должны, по крайней мере, прокомментировать, почему эти конкретные размеры были необходимы.

double arithmeticAverage;
char sequenceType;

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

float Array[SIZE_OF_GENERIC_ARRAY];
int Fibonacci[SIZE_OF_FIBONACCI_ARRAY];

Никогда не используйте массивы C-стиля. Они подходят для совместимости с B или BCPL, а не потому, что их поведение хорошее . Это не так. Они чрезвычайно небезопасны. Вместо этого вы можете использовать std::array<float, size> или std::array<int, size>. std::array живет в <array> и действует как реальный тип значения и стандартный контейнер.

Кроме того, вся статья _tmain совершенно не нужна, это удержание в наследство от 1995 года, которое больше не используется. Используйте main, если вы не знаете, что это такое на самом деле. Вам также не нужен этот stdafx дерьмо, хотя для того, чтобы убедить Visual Studio заткнуться, требуется немного знаний.

Теперь, как вы правильно заметили, ваши функции mean и standardDeviation являются полными дубликатами w.r.t. float и int. Вы можете легко реализовать их как одну функцию шаблона для обоих, но их также можно гораздо легче определить, используя соответствующие стандартные алгоритмы, которые живут в <algorithm> и <numeric>

Наконец, outputMean и outputStandardDeviation - бесполезный мусор, их логика должна быть только в main (также, не всегда ли они используют ужасно названный массив, а не массив Фибоначчи, даже если пользователь попросил Fib?)

ответил DeadMG 2 J000000Wednesday14 2014, 18:42:46
10

Ваш код, как правило, правильный, но ваш расчет стандартного отклонения неэффективен.

for (int i = 0; i < SIZE_OF_GENERIC_ARRAY; i++)
{
    tempSum += pow((Array[i] - mean(Array, SIZE_OF_GENERIC_ARRAY)), 2);
}

Это вызовет функцию mean один раз для каждого элемента массива, а mean аналогично итерации через массив. Если массив содержит миллион элементов, это может занять некоторое время.

Лучше всего вызвать mean один раз :

float arrayMean = mean(Array, SIZE_OF_GENERIC_ARRAY);
for (int i = 0; i < SIZE_OF_GENERIC_ARRAY; i++)
{
    tempSum += pow((Array[i] - arrayMean), 2);
}

В языке алгоритмов ваше решение - \ $ O (n ^ 2) \ $, а вторая версия - \ $ O (n) \ $.

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

P.S. Вы также можете рассчитать среднее и стандартное отклонение за один проход, если вы математически склонны.

ответил Beta 2 J000000Wednesday14 2014, 18:35:06
7

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

for (int i = 0; i < SIZE_OF_GENERIC_ARRAY; i++)
    Array[i] = i + 1;

И

for (int i = 2; i < SIZE_OF_FIBONACCI_ARRAY; i++)
    Array[i] = Array[i - 1] + Array[i - 2];

Против

for (i = 0; i < SIZE_OF_GENERIC_ARRAY; i++)
{
    sumOfElements += Array[i];
}

И

for (int i = 0; i < SIZE_OF_GENERIC_ARRAY; i++)
{
    tempSum += pow((Array[i] - mean(Array, SIZE_OF_GENERIC_ARRAY)), 2);
}

есть другие проблемы форматирования fluke, которые, я уверен, имеют отношение к ошибкам опечаток или копированию ...

    if (sequenceType == 'G' || sequenceType == 'g')
   {
       fillGenericArray(SIZE_OF_GENERIC_ARRAY);
       outputMean();
       outputStandardDeviation();
}

   else if (sequenceType == 'F' || sequenceType == 'f')
   {
       fillFibonacciArray(SIZE_OF_FIBONACCI_ARRAY);
       outputMean();
       outputStandardDeviation();
   }

   else
       cout << "\n"
            << "Invalid input. Please type 'F' or 'G'. Thank you.";
  • Возврат каретки между элементами оператора if
  • Нет скобок в инструкции else
  • Плохой отступ в выражении if

вот что должно выглядеть:

    if (sequenceType == 'G' || sequenceType == 'g')
    {
        fillGenericArray(SIZE_OF_GENERIC_ARRAY);
        outputMean();
        outputStandardDeviation();
    }
    else if (sequenceType == 'F' || sequenceType == 'f')
    {
        fillFibonacciArray(SIZE_OF_FIBONACCI_ARRAY);
        outputMean();
        outputStandardDeviation();
    }
    else
    {
       cout << "\n"
            << "Invalid input. Please type 'F' or 'G'. Thank you.";
    }

Я не знаю, как его закодировать, но я думаю, что это можно сделать, вы должны преобразовать вход в верхний регистр, а затем просто проверить на 'G' или 'F', это устранит дополнительную проверку, но по какой цене я не знаю.

, поэтому я бы преобразовал вход в верхний регистр и затем исключил проверку для строчной буквы.

sequenceType = std::toupper(sequenceType);
if (sequenceType == 'G')
{
    fillGenericArray(SIZE_OF_GENERIC_ARRAY);
    outputMean();
    outputStandardDeviation();
}
else if (sequenceType == 'F')
{
    fillFibonacciArray(SIZE_OF_FIBONACCI_ARRAY);
    outputMean();
    outputStandardDeviation();
}
else
{
   cout << "\n"
        << "Invalid input. Please type 'F' or 'G'. Thank you.";
}
ответил Malachi 2 J000000Wednesday14 2014, 19:07:51

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132