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

Вычисление характеристик массива при дополнительных ограничениях на элементы

< Лекция 1 || Лекция 3
Аннотация: Вычисление характеристик массива при дополнительных ограничениях на элементы В этом уроке обсуждается решение задачи, созданное школьником в ходе выполнения домашней работы. Решение правильное, содержит комментарии. Его недостаток в плохой структурированности решения, поскольку все оно помещено в программу main консольного проекта. Оставшаяся часть урока посвящена разбору решения этой же задачи, основанного на функциях. Эта задача позволяет продемонстрировать особенности вычисления характеристик массива – суммы, произведения, максимального и минимального элементов, в условиях, когда при вычислении характеристик на элементы накладываются дополнительные ограничения.

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

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

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

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

Напомню простенький стишок, способствующий пониманию деталей соответствующих алгоритмов:

Чтобы максимум найти
Помнить правил нужно три:
Объявить, //переменную max для хранения максимума
Задать, //начальное значение, равное минимально возможному значению
Сравнить //в цикле текущий элемент массива с переменной max
Ничего не позабыть!

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

        /// Сумма положительных элементов массива
        /// </summary>
        /// <param name="arr">массив</param>
        /// <returns>сумма положительных элементов</returns>
        int SumPositiv(int[] arr)
        {
            int sum = 0;
            int n = arr.Length;
            for (int i = 0; i < n; i++)
                if (arr[i] > 0)
                    sum += arr[i];
            return s
        }

Все три правила продолжают действовать. Первым делом вводится переменная sum, где будет накапливаться сумма элементов. Эта переменная нужным образом инициализируется. В цикле по числу элементов массива происходит последовательное прибавление элементов массива к переменной sum. Однако в отличие от классического алгоритма суммирования не все элементы массива участвуют в формировании суммы. Каждый элемент является только кандидатом на суммирование. Чтобы участвовать в суммировании элемент должен пройти фильтр. В данном случае фильтр осуществляет оператор if, который проверяет является ли элемент положительным. Если да, то он допускается к суммированию. Отрицательные элементы не участвуют в формировании суммы.

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

Рассмотрим теперь алгоритм нахождения индекса максимального элемента массива. Он также является простой модификацией алгоритма нахождения максимального элемента и удовлетворяет выше приведенным трем правилам:

/// <summary>
        /// Индекс первого максимального элемента массива
        /// </summary>
        /// <param name="arr">массив</param>
        /// <returns>индекс первого максимального элемента</returns>
        int Index_max(int[] arr)
        {
            int max = int.MinValue;
            int index_max = -1;
            int n = arr.Length;
            for (int i = 0; i < n; i++)
                if (arr[i] > max)
                {
                    max = arr[i];
                    index_max = i;
                }
            return index_max;
        }

И здесь необходимо первым делом объявить переменную max, в которой будет храниться текущее значение максимального элемента. Ее следует правильно инициализировать значением, заведомо меньшим, чем значения элементов массива, рекомендуется использовать минимально возможное значение для типа элементов массива. Затем в цикле сравнивать эту переменную с очередным элементом массива. Также, как и при вычислении суммы положительных элементов, при нахождении максимума элементы могут проходить дополнительный фильтр, например, можно искать максимальный по модулю элемент массива. При определении индекса максимального элемента необходимо помимо переменной max объявить еще одну переменную – index_max, в которой будет храниться индекс найденного максимального элемента.

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

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

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

        /// <summary>
        /// Индекс первого минимального элемента массива
        /// </summary>
        /// <param name="arr">массив</param>
        /// <returns>индекс первого минимального элемента</returns>
        int Index_min(int[] arr)
        {
            int min = int.MaxValue;
            int index_min = -1;
            int n = arr.Length;
            for (int i = 0; i < n; i++)
                if (arr[i] < min)
                {
                    min = arr[i];
                    index_min = i;
                }
            return index_min;
        }

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

        /// <summary>
        /// Произведение элементов,
        /// расположенных между первым максимальным
        /// и первым минимальным элементами массива
        /// </summary>
        /// <param name="arr">исходный массив</param>
        /// <returns>произведение элементов</returns>
        int MaxMinProduct (int[] arr)
        {
            int index_max, index_min;
            index_max = Index_max(arr);
            index_min = Index_min(arr);
            int ind_start, ind_finish;
            ind_start = Math.Min(index_max, index_min);
            ind_finish = Math.Max(index_max, index_min);
            int product = 1;
            for (int i = ind_start + 1; i < ind_finish; i++)
                product *= arr[i];
            return product;
        }

В этой функции необходимо учитывать тот факт, что заранее неизвестно, какой элемент встретится раньше – первый минимальный или первый максимальный. Поэтому введены дополнительные индексы start и finish, отмечающие начало и конец интервала, на котором вычисляется произведение элементов. Для их расчета использованы стандартные функции Max и Min из класса Math.

Конечно, этот же результат можно достичь, используя оператор if:

if(index_min < index_max)
	{ind_start = index_min; ind_finish = index_max;}
else 
	{ind_start = index_max; ind_finish = index_min;}

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

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

увеличить изображение
Рис. 3.1. Интерфейс проекта

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

private void buttonSumPositiv_Click_1(object sender, EventArgs e)
        {
            int sumpositiv = SumPositiv(arr);
            textBoxSumPositiv.Text = sumpositiv.ToString();
        }

        private void buttonMinMaxProd_Click(object sender, EventArgs e)
        {
            int maxminProd = MaxMinProduct(arr);
            textBoxMinMaxProd.Text = maxminProd.ToString();
        }

Массив arr, используемый в вычислениях определен непосредственно в программном коде. Вот его определение для примера, показанного на рис. 3.1 рис. 3.1:

int[] arr = { -5, 1, 2, 3, 4, 5, 6, 7, 8, -3 };

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

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

< Лекция 1 || Лекция 3