Опубликован: 09.12.2017 | Доступ: свободный | Студентов: 737 / 31 | Длительность: 02:06:00
Специальности: Программист
Лекция 1:

Вычисление суммы, максимального и минимального элементов небольшого множества

Лекция 1: 12

Тело функции. Два алгоритма

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

return x1 + x2 + x3;

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

Предпочтительнее другой, более сложный алгоритм, приведенный в нашем тексте программы:

int sum = 0;//вводим переменную для суммы с начальным значением 0
            sum = sum + x1; //прибавляем первое слагаемое
            sum = sum + x2; //прибавляем второе слагаемое
            sum = sum + x3; //прибавляем третье слагаемое
            return sum;		//возвращаем результат

В чем принципиальное отличие этого алгоритма? Здесь введена переменная с именем sum (заметьте, в C# имена sum и Sum различны), в которой и будет постепенно накапливаться сумма элементов множества. Важно обратить внимание на инициализацию этой переменной. Вначале ее значение равно нулю. Прибавив к ней первую переменную, получим сумму для множества из одного элемента. К этой переменной последовательно прибавляются значения элементов суммируемого множества.

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

Этот же прием с введением специальной переменной мы используем при построении функции, вычисляющей максимальный элемент:

        /// <summary>
        /// Максимум трех аргументов
        /// </summary>
        /// <param name="x1">аргумент1</param>
        /// <param name="x2">аргумент2</param>
        /// <param name="x3">аргумент3</param>
        /// <returns>максимум из(x1, x2, x3)</returns>
        int Max(int x1, int x2, int x3)
        {
          int max = int.MinValue;   //переменная max с начальным значением MinValue
          if (x1 > max) max = x1; //максимум из одного значения
          if (x2 > max) max = x2; //максимум из двух значений
          if (x3 > max) max = x3; //максимум из трех значения
          return max;		//возвращаем результат

 }

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

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

Интерфейс проекта

Для решения нашей задачи по сбору грибов построим Windows проект со следующим интерфейсом:

Интерфейс проекта "Собираем грибы"

Рис. 1.1. Интерфейс проекта "Собираем грибы"

Интерфейс проекта достаточно прост. Есть метка (label) в начале формы с заголовком проекта. Есть окошки (textbox) "кто", в которых следует задать имена сборщиков грибов, окошки "сколько", в которых указывается, кто сколько грибов собрал. И есть командные кнопки, позволяющие ответить на поставленные вопросы. Ответы на вопросы будут появляться в окне сообщений. Когда пользователь проекта нажмет соответствующую кнопку, то в ответ на это событие, обработчик события прочитает данные из окошек, вызовет соответствующую написанную нами функцию, передаст ей данные, и результат ее работы поместит в окно сообщений.

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

Вот как выглядит обработчик события командной кнопки, на которой написано "сколько собрали":

private void buttonSum_Click(object sender, EventArgs e)
        {
            int value1, value2, value3;
            value1 = int.Parse(textBoxValue1.Text);
            value2 = int.Parse(textBoxValue2.Text);
            value3 = int.Parse(textBoxValue3.Text);
            int sum = Sum(value1, value2, value3);
            textBoxMessage.Text = sum.ToString(); 
        }

Имя процедуры, представляющей обработчик события, строится из имени кнопки – buttonSum и имени события – Click.

В обработчике события объявляются три переменные. Значения эти переменные получают в соответствии с данными, прочитанными из окошек. Обратите внимание, в текстовых окнах пользователь задает значения как текст. Поэтому данные, представляющие целые числа, должны быть преобразованы, - из типа string приведены к типу int. Это преобразование выполняет метод Parse, разбирающий строку, преобразуя ее в число. Конечно, в строке должно быть записано число, чтобы такое преобразование могло выполниться без ошибок.

После ввода необходимых данных вызывается приведенная выше функция Sum, вычисляющая сумму значений. Результат помещается в окно сообщений. Все выполняется в полном соответствии с приведенным выше описанием работы обработчика событий.

Приведем уже без подробных комментариев функцию, вычисляющую максимум из трех значений:

        /// <summary>
        /// Максимум трех аргументов
        /// </summary>
        /// <param name="x1">аргумент1</param>
        /// <param name="x2">аргумент2</param>
        /// <param name="x3">аргумент3</param>
        /// <returns>максимум из(x1, x2, x3)</returns>
        int Max(int x1, int x2, int x3)
        {
          //  return Math.Max(Math.Max(x1, x2), x3);
            int max = int.MinValue; //вводим переменную для максимума с начальным значением MinValue
            if (x1 > max) max = x1; //максимум из одного значения
            if (x2 > max) max = x2; //максимум из двух значений
            if (x3 > max) max = x3; //максимум из трех значения
            return max;		//возвращаем результат
        }

А вот текст обработчика события, позволяющего вычислить максимум:

        private void buttonMax_Click(object sender, EventArgs e)
        {
            int value1, value2, value3;
            value1 = int.Parse(textBoxValue1.Text);
            value2 = int.Parse(textBoxValue2.Text);
            value3 = int.Parse(textBoxValue3.Text);
            int max = Max(value1, value2, value3);
            textBoxMessage.Text = max.ToString();
        }

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

Приведу текст соответствующего метода, решающего эту задачу:

        /// <summary>
        /// Кто достиг максимума
        /// </summary>
        /// <param name="x1">значение 1</param>
        /// <param name="x2">значение 2</param>
        /// <param name="x3">значение 3</param>
        /// <param name="name1">имя первого претендента</param>
        /// <param name="name2">имя второго претендента</param>
        /// <param name="name3">имя третьего претендента</param>
        /// <param name="max">максимум</param>
        /// <param name="name_max">имя того, кто достиг максимума</param>
        void MaxAndName(int x1, int x2, int x3,
            string name1, string name2, string name3,
            out int max, out string name_max)
        {
            max = int.MinValue; 
//вводим переменную для максимума с начальным значением MinValue
            name_max = "";
            if (x1 > max)
            {
                max = x1; name_max = name1;
                //максимум из одного значения и имя 
            }
            if (x2 > max)
            {
                max = x2; name_max = name2;
                //максимум из двух значений и имя 
            }
            if (x3 > max)
            {
                max = x3; name_max = name3;
                //максимум из трех значений и имя 
            }
        }

Заметьте, здесь метод вычисляет два результата, - значение максимума и имя того, кто достиг максимума. Поэтому метод следует реализовать как процедуру, у которой два параметра, представляющих результаты (out параметра).

Обработчик события соответствующей командной кнопки немногим отличается от выше приведенных обработчиков события. Вот его текст:

private void buttonMaxName_Click(object sender, EventArgs e)
        {
            //входные данные. Ввод значений
            int value1, value2, value3;
            string name1, name2, name3;
            value1 = int.Parse(textBoxValue1.Text);
            value2 = int.Parse(textBoxValue2.Text);
            value3 = int.Parse(textBoxValue3.Text);
            name1 = textBoxName1.Text;
            name2 = textBoxName2.Text;
            name3 = textBoxName3.Text;

            //результаты
            int max_value;
            string max_name;

            //вычисления
            MaxAndName(value1, value2, value3,
                name1, name2, name3,
                out max_value, out max_name);

            //вывод результатов
            textBoxMessage.Text = max_name + " собрал(а) грибов " +
                max_value + ". Больше всех!";
        }

Приведу снимок экрана работающего проекта, в тот момент, когда нажата кнопка, позволяющая определить того, кто собрал больше всех грибов:

Проект "Собираем грибы" в процессе работы

Рис. 1.2. Проект "Собираем грибы" в процессе работы

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

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

Задача о соревнованиях по триатлону

В соревнованиях по триатлону спортсменам нужно проплыть 1500 метров, проехать на велосипеде 40 километров и пробежать 10 километров. Из трех спортсменов Андрей лучше всех плавает, Егор быстрее бегает, а Михаил лучший на велосипеде. Известны скорости этих трех спортсменов в каждом виде состязаний. Определите время, затраченное участниками на прохождение дистанции, и кто из них стал победителем.

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

Интерфейс проекта "Соревнование по триатлону"

Рис. 1.3. Интерфейс проекта "Соревнование по триатлону"
Лекция 1: 12