Вычисление функций на последовательностях
Как правило, компьютеры прежде всего используются для обработки значительных объемов информации. В большинстве алгоритмов информация читается последовательно, от начала к концу. Поэтому в программах очень часто встречаются фрагменты кода, вычисляющие некоторую функцию на последовательности элементов.
Предположим для простоты, что последовательность элементов находится в массиве. В реальных программах она также может читаться из файла или из более сложных структур данных - например, из списка. В любом случае можно встать в начало последовательности, прочесть ее очередной элемент, а также определить, есть ли еще непрочитанные элементы.
Рассмотрим пример: дана последовательность вещественных чисел, требуется вычислить сумму ее элементов. Запишем алгоритм на неформальном языке в самом общем виде.
вещ алгоритм сумма последовательности | дано: последовательность вещественных чисел | надо: вернуть сумму ее элементов начало алгоритма | вещ s, x; | s := 0.0; | встать в начало последовательности | цикл пока есть непрочитанные элементы | | прочесть очередной элемент последовательности в (вых:x) | | s := s + x; | конец цикла | ответ := s; конец алгоритма
Здесь перед словом " алгоритм " записывается тип возвращаемого значения, т.е. " вещ " для вещественного числа. Это означает, что алгоритм можно использовать как функцию. Например, для функции " sin " можно записать выражение
y := sin(x)
При вычислении выражения сначала вызывается алгоритм (функция), вычисляющий sin, затем значение, которое возвращается этим алгоритмом, присваивается переменной y. В нашем случае можно использовать выражение
y := сумма последовательности;
для вызова алгоритма и записи возвращаемого значения в переменную y.
В случае, когда последовательность чисел находится в массиве, алгоритм выглядит следующим образом:
вещ алгоритм сумма последовательности(вх: цел n, вещ a[n]) | дано: n -- число элементов последовательности, | a[n] -- массив элементов последовательности | надо: вернуть сумму элементов последовательности начало алгоритма | вещ s; цел i; | s := 0.0; // Инициализация значения ф-ции | i := 0 | цикл пока i < n | | s := s + a[i]; // Вычисление нового значения по старому | | // значению и очередному элементу | | i := i + 1; // Переходим к следующему элементу | конец цикла | ответ := s; конец алгоритма
Здесь целочисленная переменная i используется в качестве индекса элемента массива. Она последовательно принимает значения от 0 до n-1. Очередной элемент последовательности записывается как a[i].
Отметим следующие составные части алгоритма, вычисляющего функцию на последовательности элементов:
- инициализация значения функции для пустой последовательности - в данном случае
s : = 0.0 ;
- вычисление нового значения функции по прочтении очередного элемента последовательности. Новое значение вычисляется по старому значению и очередному прочитанному элементу. В данном случае это суммирование
s : = s+a[i].
Эти две части присутствуют в любом алгоритме, вычисляющем функцию на последовательности.
Рассмотрим еще один важный пример: вычисление максимального элемента последовательности. В отличие от суммы элементов, здесь не вполне ясно, каким значением надо инициализировать максимум, то есть чему равен максимум пустой последовательности. Для того, чтобы максимум одноэлементной последовательности вычислялся правильно, надо, чтобы максимум пустой последовательности был меньше любого числа. Поэтому максимум пустой последовательности не может быть обычным числом. В математике и в программировании очень полезен следующий прием: к обычным элементам добавляется специальный воображаемый элемент с заданными свойствами. Так были изобретены ноль, отрицательные числа, иррациональные и комплексные числа и т.п. В данном случае, таким воображаемым элементом является "минус бесконечность".
вещ алгоритм максимум последовательности(вх: цел n, вещ a[n]) | дано: n -- число элементов последовательности, | a[n] -- массив элементов последовательности | надо: вернуть максимум элементов последовательности начало алгоритма | вещ m; цел i; | m := минус бесконечность; // Инициализация значения ф-ции | i := 0; | цикл пока i < n | | если a[i] > m // Вычисление нового значения по | | | то m := a[i]; // старому значению и очередному эл-ту | | конец если | | i := i + 1; | конец цикла | ответ := m; конец алгоритма
Здесь переменная m на любом шаге содержит максимальное значение для просмотренного начального отрезка последовательности, т.е. кандидата на максимум. Если очередной элемент больше, чем m, то он запоминается в переменной m и становится новым кандидатом на максимум.
Значение "минус бесконечность" в случае операции взятия максимума двух чисел обладает следующим замечательным свойством: для всякого числа x выполняется равенство
max(минус бесконечность,x) = x
Можно сравнить с операцией сложения:
0+x = x
Таким образом, значение "минус бесконечность" играет роль нуля для операции взятия максимума двух чисел. Ноль - это нейтральный элемент для операции сложения: будучи прибавленным слева к произвольному числу x, он не изменяет числа x. Точно так же значение "минус бесконечность" является нейтральным для операции взятия максимума.
Для операции "минимум" нейтральным элементом является "плюс бесконечность". Таким образом, алгоритм нахождения минимума последовательности выглядит следующим образом:
вещ алгоритм минимум последовательности(вх: цел n, вещ a[n]) | дано: n -- число элементов последовательности, | a[n] -- массив элементов последовательности | надо: вычислить минимум элементов последовательности начало алгоритма | вещ m; цел i; | m := плюс бесконечность; // Инициализация значения ф-ции | i := 0; | цикл пока i < n | | если a[i] < m // Вычисление нового знач. по старому | | | то m := a[i]; // значению и очередному элементу | | конец если | | i := i + 1; | конец цикла | ответ := m; конец алгоритма