Задания к самостоятельной работе




1. Дан одномерный массив. Написать функцию, определяющую минимальный, максимальный элементы массива и среднее арифметическое минимального и максимального элементов. Кроме того, программа должна иметь функцию ввода одномерного массива и функцию вывода.

2. Написать функцию перемножения матриц А размером nхm и В размером mхl. Элементы результирующей матрицы получить с помощью следующей формулы. Массивы должны быть динамическими.

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

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

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

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

7. В одномерном массиве, состоящем из n вещественных чисел, вычислить:

а) количество элементов массива, меньших С;

б) сумму положительных элементов, расположенных после первого положительного элемента.

Преобразовать массив таким образом, чтобы сначала располагались все элементы, целая часть которых лежит в интервале [a, b], а потом – все остальные.

Программа должна быть составлена с использованием функций.


Лабораторная работа 4

Перегрузка функций

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

Перегруженные функции не могут отличаться только типом возвращаемого значения.

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

# include < iostream >

using namespace std;

double avg (int a, int b);

double avg (int a, int b, int c);

double avg (double a, double b);

double avg (double a, double b, double c);

int main()

{

int x, y, z;

cout << ” Enter 3 integers \n ”;

cin >> x >> y >> z;

cout << ” average value of 2 numbers = ” << avg (x, y);

cout << ” average value of 3 numbers = ” << avg (x, y, z);

double n, m, k;

cout << ” Enter 3 real numbers \n ”;

cin >> n >> m >> k;

cout << ” average value of 2 real numbers = ” << avg (n, m);

cout << ” average value of 3 real numbers = ” << avg (n, m, k);

return 0;

}

double avg (int a, int b) { return (a + b) / 2.0;}

double avg (int a, int b, int c) { return (a + b + c) / 3.0; }

double avg (double a, double b) { return (a + b) / 2; }

double avg (double a, double b, double c) {return (a + b + c) /3;}

Шаблоны функции

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

Использовать несколько определений идентичных функций, работающих с данными разного типа, не эффективно. В этом случае следует использовать шаблоны функции. При этом определение и прототип функции начинаются со строки template < class T >. Эта строка является префиксом шаблона и указывает компилятору, что следующее за ним определение функции является шаблоном, а Т - параметром типа. Слово class в этом случае обозначает тип. В качестве Т может быть указан любой тип.

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

Пример: универсальная функция сортировки.

 

# include < iostream.h >

template < class T >

void sort (T a[ ], int size);

main () {

char c [ 8 ] = {‘ p ’, ’ r ’, ’ o ’, ’ g ’, ’ r ’, ’ a ’, ’ m ’, ’ \0 ’ };

sort (c, 8);

int A [ 5 ] = { 5, 10, 1, 4, 9 };

sort (A, 5);

double B [ 4 ] = { 3.2, 1.5, 9.8, 2.8 };

sort (B, 4);

return 0;

}

template < class T >

void sort (T a [ ], int size) {

int i, P;

T D;

for (p = 1; p <= size - 1; p ++)

for (i = 0; i < size - 1; i ++)

if (a [ i ] > a [ i + 1 ]) {

D = a [ i ];

a [ i ] = a [ i + 1 ];

a [ i +1] = D;

}

Рекурсивные функции

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

Рекурсивная задача в общем случае разбивается на два этапа. Для решения задачи вызывается рекурсивная функция. Эта функция знает, как решать только простейшую часть задачи — так называемую базовую задачу (или несколько таких задач). Если эта функция вызывается для решения базовой задачи, она просто воз­вращает результат. Если функция вызывается для решения более сложной задачи, она делит эту задачу на две части: одну часть, которую функция умеет решать, и другую, которую функция решать не умеет. Чтобы сделать рекурсию выполнимой, последняя часть должна быть похожа на исходную задачу, но быть по сравнению с ней несколько проще или несколько меньше. Поскольку эта новая задача подобна исходной, функция вызывает новую копию самой себя, чтобы начать работать над меньшей проблемой — это называется рекурсивным вызовом, или шагом рекурсии. Шаг рекурсии вклю­чает ключевое слово return, так как в дальнейшем его результат будет объ­единен с той частью задачи, которую функция умеет решать, и сформируется конечный результат, который будет передан обратно в исходное место вызова, возможно, в main.

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

Недостаток рекурсии: повторный запуск рекурсивного механизма вызовов функции приводит к росту накладных расходов: к нарастающим затратам процессорного времени и требуемого объема памяти.

Как пример рассмотрим рекурсивную программу для расчета факториала.

Факториал неотрицательного целого числа n, записываемый как n!, равен n*(n-1)*(n-2)*…*1, причем считается, что 1! = 1 и 0! = 1. Например, 5! вычисляется как 5 x 4 x 3 x 2 x 1 и равен 120.

Факториал целого числа, number, большего или равного 0, может быть вычислен итеративно(нерекурсивно) с помощью оператора for следующим образом:

factorial = 1;

for (int counter = number; counter >=1; counter--)

factorial *= counter;

Теперь используем рекурсию для вычисления и печати факториалов целых чисел от 0 до 10. Рекурсивная функция factorial сначала проверяет, истинно ли условие завершения рекурсии, т.е. меньше или равно 1 значение number. Если действительно number меньше или равно 1, factorial возвра­щает 1, никаких дальнейших рекурсий не нужно и программа завершает свою работу. Если number больше 1, оператор

return number * factorial (number - 1);

представляет задачу как произведение number и рекурсивного вызова factorial, вычисляющего факториал величины number-1. Отметим, что factorial (number - 1) является упрощенной задачей по сравнению с исходным вычислением factorial (number).

В объявлении функции factorial указано, что она получает параметр типа unsigned long и возвращает результат типа unsigned long. Это является крат­кой записью типа unsigned long int. Описание языка C++ требует, чтобы переменная типа unsigned long int хранилась по крайней мере в 4 байтах (32 битах), и таким образом могла бы содержать значения в диапазоне по крайней мере от 0 до 4294967295. (Тип данных long int также хранится по крайней мере в 4 байтах и может содержать значения по крайней мере в диапазоне от 2147483647). Функ­ция factorial начинает вырабатывать большие значения так быстро, что даже unsigned long не позволяет нам напечатать много значений факториала до того, как будет превышен допустимый предел переменной unsigned long.

// Рекурсивная функция факториала

# include < iostream >

unsigned long factorial (unsigned long);

main ()

{ for (int i = 0; i <= 10; i++)

cout << i << “! = “ << factorial (i) << endl;

return 0;

}

// рекурсивное описание функции вычисления факториала

unsigned long factorial (unsigned long number)

{ if (number <= 1) return 1;

else return (number * factorial (number – 1);

}



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2017-04-04 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: