Программирование >>  Динамические структуры данных 

1 ... 8 9 10 [ 11 ] 12 13 14 ... 38


#include <iostream.h> #include <iomanip.h> void main(){

const int nrow - 10. ncol - 20:

int a[nrow][ncol]:

int i. j:

cout Введите элементы массива: endl: for (i - 0: i < nrow: i++) for (j - 0: j < ncol: cin a[i][j]:

for (i = 0: i < nrow: i++) { for (j - 0: j < ncol: cout setw(4) a[i][j] cout endl:

int n pos el: float s - 0:

for (i - 0: i < nrow: i++) { nj)os el 0:

for (j - 0: j < ncol: { s +- a[i][j]:

if (a[i][j] > 0) nj)os el++:

cout Строка: i кол-во: n pos el endl:

s /- nrow * ncol:

cout Среднее арифметическое:

s endl:

Размерности массива заданы именованными константами, что позволяет легко их изменять. Для упрощения отладки рекомендуется задать небольшие значения этих величин или приготовить тестовый массив в текстовом файле и изменить программу так, чтобы она читала значения из файла (см. задачу 4.2, с. 80, а также Учебник, с. 276,280).

Составляйте тестовые примеры таким образом, чтобы; строки массива содержали разное количество отрицательных элементов (ни одного элемента, один и более элементов, все элементы).

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

Тем не менее, здесь следует обратить внимание на два момента. Во-первых, требуется еще до написания алгоритма решить, каким образом будут храниться резуль-

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

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

СОВЕТ-

Записывайте операторы инициализации накапливаемых в цикле величин непосредственно перед циклом, в котором они вычисляются.

После ввода значений предусмотрен их контрольный вывод на экран. Для того чтобы элементы матрицы располагались один под другим, используется манипулятор setw(), устанавливающий для очередного выводимого значения ширину поля в четыре символа. Для использования манипулятора необходимо подключить к программе заголовочный файл <i omani р. h>. После каждой строки выводится символ перевода строки endl.

При написании вложенных циклов следите за отступами. Все операторы одного уровня вложенности должны начинаться в одной и той же колонке. Это облегчает чтение программы и, следовательно, поиск ошибок. По вопросу расстановки фигурных скобок существуют разные мнения специалистов. В настоящее время наиболее распространенными являются два стиля: стиль 1TBS (One True Bracing Style), которого придерживались основоположники языка С - Б. Керниган (Brian Kerni-ghan) и Д. Ритчи (Dennis Ritchie), и стиль Алмена (Eric Allman). Приведем отрывок кода, написанного в стиле 1TBS:

for (j - 0: j < MAX LEN: { fooO:

Этот же отрывок в стиле Алмена выглядит так: for (j = 0: j < MAX LEN:

fooO;

Наш выбор, естественно, остановился на единственно верном стиле.



Динамические массивы

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

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

const int m = 5: cin n:

int (*a)[m] = new int [n][m]; 1

int ** b = (int **) new int [n][m]: 2

В этом фрагменте показано два способа создания динамического массива. В операторе 1 адрес начала выделенного с помощью new участка памяти присваивается переменной а, определенной как указатель на массив из m элементов типа i nt. Именно такой тип значения возвращает в данном случае операция new. Скобки необходимы, поскольку без них конструкция интерпретировалась бы как массив указателей. Всего вьщеляется п элементов.

В операторе 2 адрес начала выделенного участка памяти присваивается переменной Ь, которая описана как указатель на указатель на int , поэтому перед присваиванием требуется выполнить преобразование типа.

Строго говоря, по стандарту в этом случае рекомендуется применять другую операцию преобразования типа (см. Учебник, с. 238), но старые компиляторы могут ее не поддерживать:

int ** b = reinterpret cast<int **> (new int [n][m]);

Обращение к элементам динамических массивов производится точно так же, как к элементам обычных , с помощью конструкции вида a[i][j].

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

Более универсальный и безопасный способ выделения памяти под двумерный массив, когда обе его размерности задаются на этапе выполнения программы, приведен ниже: int nrow, ncol:

cout Введите количество строк и столбцов : : cin nrow ncol:

int **a = new int *[nrow]: 1

for(int i = 0: i < nrow: i++) 2

a[i] = new int [ncol]: 3

В операторе 1 объявляется переменная типа указатель на указатель на int и выделяется память под массив указателей на строки массива (количество строк - nrow). В операторе 2 организуется цикл для выделения памяти под каждую строку массива. В операторе 3 каждому элементу массива )гказателей на строки присваивается адрес начала участка памяти, выделенного под строку двумерного массива. Каждая строка состоит из ncol элементов типа int (рис. 4.2).

int**a

int a[nrow]

inta[nrow][ncol]


nstb

Pmc. 4.2. Схема динамической области памяти, выделяемой под массивы

ВНИМАНИЕ --------

Освобождение памяти из-под массива с любым количеством измерений выполняется с помощью операции delete [].

Задача 4.2. Номер столбца из положительных элементов

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

Блок-схема алгоритма приведена на рис. 4.3. Для решения этой задачи матрицу необходимо просматривать по столбцам. При этом быстрее меняется первый индекс (номер строки). Сделать вывод о том, что какой-либо столбец содержит только положительные элементы, можно только после просмотра столбца целиком; зато если в процессе просмотра встретился отрицательный элемент, можно сразу переходить к следующему столбцу.



[ Начало ] I Ввод массива /

nume-l

Х J = 1.ncol

allj)08lt = tnie

i = 1. хтну

Вывод номера столбца


all posite false

num j

Столбцов нет

Рис. 4.3. Блок-схема алгоритма решения задачи 4.2

Эта логика реализуется с помощью переменной-флага all posit, которая перед началом просмотра каждого столбца устанавливается в значение true, а при нахождении отрицательного элемента опрокидывается в fal se. Если все элементы столбца положительны, флаг не опрокинется и останется истинным, что будет являться признаком присутствия в матрице искомого столбца. Если столбец найден, просматривать матрицу дальше не имеет смысла, поэтому выполняется выход из цикла и вывод результата.

#include <iestream.h>

#include <iomanip.h>

int mainOI int nrow. ncol:

cout Введите количество строк и столбиов: :

cin nrow ncol: ввод размерности массива

int i. j:

int **a new int *[nrow]: выделение памяти под массив

for(i = 0; i < nrow: i++) a[i] = new int [ncol]: cout Введите элементы массива: endl: for (i = 0: i < nrow: i-н-) for (j = 0: j < ncol: cin a[i][j]; ввод массива

for (i - 0: i < nrow: i++){ for (j - 0: j < ncol: j-н-) cout setw(4) a[i][j] : cout endl:}

int num -1: bool allj)osit:

for (j - 0: j < ncol: { просмотр no столбцам all posit = true:

for (i 0: i < nrow: i++) анализ элементов столбца

if (a[i][j] < 0) { all posit - false: break: } if (all posit) { num - j: break: }

if ( -1 - num ) cout Столбцов нет endl: el se cout Номер столбца: num endl;

return 0:

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

Можно обойтись без анализа переменной rum, да и вообще без этой переменной, если вывести номер столбца сразу после его определения, после чего завершить программу. Этот вариант приведен ниже. Заодно продемонстрированы простейшие способы работы с файлами.

СОВЕТ--=-\--

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

Распространенной ошибкой при проверке на равенство является использование вместо него операции присваивания (-). Будьте внимательны! Есть один прием, повышающий надежность кодирования таких выражений: на первом месте нужно записать константу, а после знака поместить имя переменной; в этом случае потерю одного символа обнаружит компилятор.



1 ... 8 9 10 [ 11 ] 12 13 14 ... 38

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.002
При копировании материалов приветствуются ссылки.
Яндекс.Метрика