Лабораторные работы / z9411_КафкаРС_лр_9_fixed3
.docxМИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ
федеральное государственное автономное образовательное учреждение высшего образования
«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ АЭРОКОСМИЧЕСКОГО ПРИБОРОСТРОЕНИЯ»
(ГУАП)
КАФЕДРА № 44
Преподаватель
канд. техн. наук, доцент Бариков Л. Н.
Отчёт
по лабораторной работе №9
по дисциплине ОСНОВЫ ПРОГРАММИРОВАНИЯ
на тему: «Динамические массивы»
Работу выполнил
студент гр. Z9411 Кафка Р. С.
Санкт-Петербург
2020
Лабораторная работа №9
Динамические массивы
Цель лабораторной работы: изучение структурной организации динамических массивов и способов доступа к их элементам с использованием указателей; совершенствование навыков процедурного программирования на языке C/C++ при решении задач обработки динамических массивов.
Задание на программирование: используя технологию процедурного программирования, разработать программу обработки одномерных и двумерных (матриц) динамических массивов в соответствии с индивидуальным заданием.
Порядок выполнения работы:
1. Получить у преподавателя индивидуальное задание и выполнить постановку для каждой из задач: сформулировать условие, определить входные и выходные данные, их ограничения.
2. Разработать математические модели для каждой из задач: описать с помощью формул и рисунков структуру массивов и процесс их преобразования.
3. Построить схемы алгоритмов решения задач и основных функций.
4. Составить программу на языке C/C++.
5. Входные данные на этапах тестирования и демонстрации работы преподавателю должны задаваться либо с использованием специально подобранных арифметических формул, либо вводиться с клавиатуры по запросу. Датчики псевдослучайных чисел использовать запрещается.
Если это не оговорено в конкретном варианте задания, значения элементов в каждом исходном массиве должны быть разными.
6. Выходные данные должны выводиться на экран с пояснениями. Операторы вывода результатов работы должны находиться либо в функции main(), либо в специальной функции вывода (например, преобразованного массива), вызов которой осуществляется из функции main().
7. Проверить и продемонстрировать преподавателю работу программы на полном наборе тестов, в том числе с ошибочными входными данными. Входные и выходные массивы должны выводиться в одном и том же формате.
8. Использовать стандартные потоковые объекты ввода/вывода cin и cout.
9. Оформить отчет о лабораторной работе в составе: постановка задачи, математическая модель, схема алгоритма решения, текст программы, контрольные примеры (скриншоты).
Вариант №4. (студ. билет 2019/3603)
Формулировка задания:
А. Дан массив a0, a1, a2, …, an-1. Определить абсолютную величину произведения значений элементов массива с чётными номерами, лежащих между элементом с минимальным значением и первым элементом массива с отрицательным значением.
Б. В заданной квадратной матрице размера 2n*2n найти среднее арифметическое значений отрицательных элементов области 6 (см. рисунок).
Решение задачи вариант A:
А. Дан массив a0, a1, a2, …, an-1. Определить абсолютную величину произведения значений элементов массива с чётными номерами, лежащих между элементом с минимальным значением и первым элементом массива с отрицательным значением.
Математическая модель решения
Решение задачи начинается с ввода исходных данных. Прежде всего, необходимо ввести значение (n) размера массива.
После этого необходимо задать значения всех элементов массива. Доступ к элементам массива осуществляется по их индексу (номеру данного элемента массива). Поэтому перебираем все индексы элементов массива от 0 до n-1 (нумерация элементов массива начинается с 0) и задаём значения элементов с текущими номерами.
Пусть исходный массив имеет вид (n=10):
0 |
1 |
|
|
|
|
|
|
n-2 |
n-1 |
4 |
-3 |
7 |
2 |
-5 |
-6 |
3 |
-2 |
-7 |
5 |
Теперь можно приступать к решению задачи. Вначале определяем номер элемента с минимальным значением. Принимаем за минимум первый по счёту элемент. Используем цикл, в котором перебираем значения элементов массива с 1 до n-1. Если значение меньше первого, то фиксируем индекс этого элемента i_min = i. Для упрощения дальнейшего кода присваиваем значение переменной min с помощью ссылки на переменную (&min).
Далее находим номер первого отрицательного элемента i_neg. Так же перебирая индексы элементов массива с 1 до n-1. Проверяем по условию чтобы значение было отрицательным (< 0). Как только оно нашлось, мы фиксируем номер элемента в i_neg, присваиваем значение в переменную neg с помощью ссылки (&neg). Завершаем цикл командой break, чтобы цикл не продолжил искать последующие отрицательные элементы. В случае если в массиве не будет отрицательных элементов, программа остановится, выведя ошибку на экран. После чего программу можно будет ещё раз запустить или завершить.
Затем, для корректной работы программы, проверяем: не совпадают ли минимальный элемент массива с первым отрицательным элементом, т.к. при совпадении подсчитать абсолютную величину произведения будет не из чего (между одинаковыми элементами нет чисел). Если всё в порядке – программа продолжает работу, если нет – остановится, выведя ошибку на экран с дальнейшим перезапуском или завершением.
В конце подсчитываем абсолютную величину произведения значений элементов массива mult. В программе сначала присваиваем значению mult = 1, находить величину будем с помощью функции, в которой присвоим значение для переменной с помощью ссылки (&mult). Для этого запускаем цикл с шагом 2, т.к. нам нужны чётные номера. Значения в нём перебираем в зависимости того, какой элемент будет в массиве первый:
- Если первое отрицательное число стоит раньше минимального, то перебираем индексы от первого отрицательного значения i_neg до минимального значения i_min.
- Если минимальное число стоит раньше первого отрицательного, то перебираем индексы от минимального i_min до первого отрицательного значения i_neg. (Но, логически рассуждая, такого быть не может в данных условиях постановки задачи, т.к. либо в этом массиве не будет отрицательных чисел, либо оба элемента массива будут одинаковыми. Оба этих случая приведут к ошибке.)
Как только цикл закончится проверяем значение на наличие минуса, при необходимости отбрасываем его чтобы получилось абсолютное значение.
В результате абсолютная величина произведения значений элементов массива с чётными номерами, лежащих между элементом с минимальным значением и первым элементом массива с отрицательным значением зафиксирована в переменной mult. Выводим её на экран.
Для рассматриваемого примера otr=-3, min=-7, элементы с чётными номерами: 7, -5, 3. Абсолютная величина произведения значений элементов массива с чётными номерами mult=105
0 |
1 |
2 |
|
4 |
|
6 |
|
m-2 |
m-1 |
4 |
-3 |
7 |
2 |
-5 |
-6 |
3 |
-2 |
-7 |
5 |
|
iotr |
|
|
|
|
|
|
imin |
|
Задача решена.
Схема алгоритма подсчета абсолютной величины произведения значений элементов массива (функция absoluteValueMult)
Схема алгоритма поиска номера минимального значения(функция minValue) и поиска номера первого отрицательного значения(функция firstNegative)
Текст программы (вариант А)
/*Массивы динамические одномерные
Определить абсолютную величину произведения значений элементов
массива с чётными номерами, лежащих между элементом с минимальным
значением и первым элементом массива с отрицательным значением.*/
#include <iostream>
#include <locale.h>
using namespace std;
typedef int telem; //объявление типа элемента массива
typedef telem* tmas; //объявление типа "указатель на telem"
void fillArray(tmas arr, int n);
void showArray(tmas arr, int n);
int minValue(tmas arr, telem &min, int n);
int firstNegative(tmas arr, telem &neg, int n);
void areEqual(int i, int j);
void absoluteValueMult(tmas arr, telem &mult, int i_min, int i_neg);
int main()
{
int n; //размер массива
int i; //для выбора повторить/завершить программу
setlocale(LC_ALL, "Russian");
cout << "\n Определить абсолютную величину произведения значений элементов";
cout << "\n массива с чётными номерами, лежащих между элементом с минимальным";
cout << "\n значением и первым элементом массива с отрицательным значением.";
//Ввод исходных данных
cout << "\n Введите количество элементов массива: ";
cin >> n;
tmas arr = new telem[n]; /*создание переменной-указателя на telem,
выделение динамической памяти под массив
адрес начала области заносится в arr*/
int i_min; //номер элемента с минимальным значением
int i_neg; //номер первого элемента с отрицательным значением
telem min; //значение минимального элемента
telem neg; //значение первого отрицательного элемента
telem mult = 1; //значение абсолютного произведения
fillArray(arr, n);
showArray(arr, n);
i_min = minValue(arr, min, n); //Поиск номера элемента с минимальным значением
i_neg = firstNegative(arr, neg, n); //Поиск номера первого элемента с отрицательным значением
cout << " Элемент с минимальным значением: " << min << ", под номером: " << i_min << endl;
cout << " Первый элемент массива с отрицательным значением: " << neg << ", под номером: " << i_neg << endl;
areEqual(i_min, i_neg); //Проверка: между элементами должен быть интервал
absoluteValueMult(arr, mult, i_min, i_neg);
cout << "\n Абсолютная величина произведения значений элементов массива ";
cout << "\n с чётными номерами, лежащие между элементом с минимальным значением ";
cout << "\n и первым элементом массива с отрицательным значением: " << mult << endl;
delete[] arr; //освобождение динамической памяти
cout << "\n Повторить-1, Выход-2: ";
cin >> i;
if (i == 1) main();
return 0;
}
void absoluteValueMult(tmas arr, telem &mult, int i_min, int i_neg)
{
int start, stop;
if (i_neg < i_min) { //Если первое отрицательное число стоит раньше минимального
stop = i_min;
if (i_neg % 2 == 0) //проверка на чётность
start = i_neg + 2; //чётное - начать со следующего чётного
else start = i_neg + 1;
}
else { //Если минимальное число стоит раньше первого отрицательного
stop = i_neg;
if (i_min % 2 == 0)
start = i_min + 2;
else start = i_min + 1;
}
cout << "\n Элементы с чётными номерами: ";
for (int i = start; i < stop; i += 2) {
cout << *(arr + i) << " ";
mult *= *(arr + i);
}
if (mult < 0) mult *= -1;
}
int minValue(tmas arr, telem &min, int n)
{
int i_min = 0; //За минимум принимаем первый по счёту элемент
min = arr[0];
for (int i = 1; i < n; i++) {
if (min > *(arr + i)) {
min = *(arr + i);
i_min = i;
}
}
return i_min;
}
int firstNegative(tmas arr, telem& neg, int n)
{
int i;
int i_neg;
for (int i = 0; i < n; i++) {
if (*(arr + i) < 0) {
neg = *(arr + i);
i_neg = i;
return i_neg;
}
}
cout << " В данном массиве нет отрицательных элементов. Выполнение программы невозможно. ";
cout << "\n Повторить-1, Выход-2: ";
cin >> i;
if (i == 1) main();
exit(1);
}
void fillArray(tmas arr, int n)
{
cout << " Введите одной строкой элементы массива из ";
cout << n << " чисел и нажмите <Enter>" << endl << " ";
for (int i = 0; i < n; i++) {
cin >> *(arr + i);
}
}
void showArray(tmas arr, int n)
{
cout << " Массив имеет вид: " << endl;
for (int i = 0; i < n; i++)
{
cout << *(arr + i) << " ";
}
cout << endl;
}
void areEqual(int i, int j) {
int k;
if (i == j) {
cout << " В данном массиве оба элемента совпадают по номеру и значению. Выполнение программы невозможно. ";
cout << "\n Повторить-1, Выход-2: ";
cin >> k;
if (k == 1) main();
exit(1);
}
}
Скриншот результатов выполнения программы (вариант А)
Решение задачи вариант Б:
Б. В заданной квадратной матрице размера 2n*2n найти среднее арифметическое значений отрицательных элементов области 6 (см. рисунок).
Математическая модель решения
Решение задачи начинается с ввода исходных данных. Из формулировки задачи понятно, что исходная матрица квадратная с чётным числом (2n) строк и столбцов. Следовательно, прежде всего, необходимо ввести значение (n) половины размера квадратной матрицы.
После этого необходимо задать значения всех элементов матрицы. Доступ к элементам двумерного массива (матрицы) осуществляется по двум индексам: номеру строки и номеру столбца, на пересечении которых находится данный элемент массива (нумерация строк и столбцов начинается с 0). Поэтому перебираем все строки (с 0-ой до 2n-1). Внутри каждой строки перебираем все столбцы (с 0-ого до 2n-1) и задаём значения элементов, лежащих на пересечении строки и столбца с текущими номерами.
Пусть в качестве примера исходная матрица имеет вид (n=5):
|
0 |
1 |
|
|
n-1 |
n |
|
|
2n-2 |
2n-1 |
0 |
-0 |
-1 |
-2 |
-3 |
-4 |
-5 |
-6 |
-7 |
-8 |
-9 |
1 |
-10 |
-11 |
-12 |
-13 |
-14 |
-15 |
-16 |
-17 |
-18 |
-19 |
|
-20 |
-21 |
-22 |
-23 |
-24 |
-25 |
-26 |
-27 |
-28 |
-29 |
|
-30 |
-31 |
-32 |
-33 |
-34 |
-35 |
-36 |
-37 |
-38 |
-39 |
n-1 |
-40 |
-41 |
-42 |
-43 |
-44 |
-45 |
-46 |
-47 |
-48 |
-49 |
n |
-50 |
-51 |
-52 |
-53 |
-54 |
-55 |
-56 |
-57 |
-58 |
-59 |
|
-60 |
-61 |
-62 |
-63 |
-64 |
-65 |
-66 |
-67 |
-68 |
-69 |
|
-70 |
-71 |
-72 |
-73 |
-74 |
-75 |
-76 |
-77 |
-78 |
-79 |
2n-2 |
-80 |
-81 |
-82 |
-83 |
-84 |
-85 |
-86 |
-87 |
-88 |
-89 |
2n-1 |
-90 |
-91 |
-92 |
-93 |
-94 |
-95 |
-96 |
-97 |
-98 |
-99 |
Теперь можно приступать к решению задачи. Требуется найти среднее арифметическое значений отрицательных элементов области 6 (т.е. значения элементов строк, лежащие ниже побочной диагонали и значения элементов столбцов, лежащие левее центра матрицы).
Поэтому в нахождении участвуют значения элементов строк с 0 до n-1 и элементы столбцов ниже побочной диагонали с n до 2n-2. Если значение элемента попадает в нужную область, то мы прибавляем его в общее значение суммы (sum) и увеличиваем счётчик элементов (count) на 1. Таким образом у нас получится общая сумма (sum), которую нужно поделить на количество (счётчик) этих элементов (count) и получится среднее значение (avg).
Задача решена.
Схема алгоритма нахождения среднего арифметическое значений отрицательных элементов области 6
Текст программы (вариант Б)
/*Массивы динамические двумерные.
В заданной квадратной матрице размера 2n*2n
найти среднее арифметическое значений
отрицательных элементов области 6 (см. рисунок).*/
#include<iostream>
#include<locale.h>
using namespace std;
typedef int telem; //определение типа элементов массива
typedef telem *tstr; //определение типа "указатель на telem"
typedef tstr *tmatr; //тип "указатель на указатель на telem"
void fillArray(tmatr, int);
void showArray(tmatr, int);
double calcArithmeticMean(tmatr arr, int n);
int main()
{
int n; //число строк (столбцов) матрицы
double avg;
tmatr arr; //переменная-указатель на указатель на telem
setlocale(LC_ALL, "Russian");
cout << " В заданной квадратной матрице размера 2n*2n \n";
cout << " найти среднее арифметическое значений \n";
cout << " отрицательных элементов области 6. \n";
cout << " Введите половину размера матрицы: n = ";
cin >> n;
arr = new tstr[2 * n]; /*выделение динамической памяти под массив
указателей на строки массива*/
for (int i = 0; i < 2 * n; i++) //выделение памяти под каждую строку:
*(arr + i) = new telem[2 * n]; /*каждому элементу массива указателей
на строки присваивается адрес начала
области памяти, выделяемой под строку*/
fillArray(arr, 2 * n);
cout << " Исходная матрица:\n";
showArray(arr, 2 * n);
avg = calcArithmeticMean(arr, n);
cout << " Среднее арифметическое значений отрицательных элементов:\n";
cout << avg << endl;
cout << endl << " Для завершения нажмите <Enter>";
//Освобождение динамической памяти
for (int i = 0; i < n; i++)
delete *(arr + i);
delete[]arr;
return 0;
}
void fillArray(tmatr arr, int n)
{
cout << " Значения элементов";
cout << " массива размера " << n << "x" << n;
cout << "\n при тестировании вводятся автоматически:" << endl;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
*(*(arr + i) + j) = -(10 * i + j);
}
void showArray(tmatr arr, int n)