Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Visual_C_console.pdf
Скачиваний:
34
Добавлен:
16.05.2015
Размер:
954.14 Кб
Скачать

69

if (a[i] < 0) // Элемент меньше нуля, установить флаг

{

flag ^= 1; // «Щелкушка» переключения флага (см. стр. 38) continue; // Текущий элемент не заменять

}

if (flag && a[i] >= 0) a[i] = 0; // Флаг установлен! Замена нулями

}

for (int i = 0; i < SIZE; i++) // Вывод всего массива cout << a[i] << " ";

_getch();

}

По условию задачи заменяются нулями элементы между отрицательными числами. При обнаружении отрицательного элемента флаг переключается в противоположное состояние. Перед началом цикла состояние флага «ложно», поэтому при появлении отрицательного элемента флаг переключается в состояние «истинно» и цикл продолжается за счет оператора continue; без замены текущего элемента. С другой стороны, замена выполняется, если флаг имеет состояние «истинно». Но сначала проверяется знак у элемента, а затем проверяется флаг. Тогда при появлении следующего отрицательного элемента сначала переключится флаг, и замены будут выключены.

В тексте программы использована «щелкушка» (описание этой «щелкушки» см. на стр. 38), основанная на целых числах. Но можно применять и булевские переменные. Для этого надо:

int flag = 0; заменить на bool flag = false;

и

flag ^= 1; заменить на flag ^= true;

Многомерные массивы

В языке С++ допускается работа с массивами с размерностью больше единицы (двухмерными, трехмерными и т.д.). В двухмерных массивах, или, как их часто называют, - матрицах, размещение эле-

70

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

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

int n[4][3];

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

n[0][0] n[0][1] n[0][2] n[0][3] n[1][0] n[1][1] n[1][2] n[1][3] n[2][0] n[2][1] n[2][2] n[2][3]

Как следует из назначения индексов матрицы, одинаковым в каждой строке является первый индекс, а в каждом столбце второй индекс.

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

n[0][0] n[0][1] n[0][2] n[0][3] n[1][0] n[1][1] n[1][2] и т.д.

Обработка элементов матрицы специфична выбором направления обработки: по строкам, столбцам или диагоналям матрицы.

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

Пусть объявлена матрица

71

double a[4][4];

Ее элементы с математической точки зрения располагаются следующим образом:

a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] a[3][0] a[3][1] a[3][2] a[3][3]

Выберем, например, 3-ю строку (первый индекс равен 2) и будем последовательно изменять 2-й индекс, тогда изменение индексов (или порядок обращения к элементам матрицы) будет осуществляться в указанной ниже последовательности:

a[2][0] a[2][1] a[2][2] a[2][3] ,

т. е обработка выполняется по строкам.

Выберем теперь столбец, второй индекс у которого равен 3, и будем последовательно изменять 1-й индекс, тогда обращение к элементам матрицы будет выполняться в указанном ниже порядке:

a[0][3] a[1][3] a[2][3] a[3][3] ,

т. е обработка выполняется по столбцам.

Назначим для первого индекса матрицы переменную i, a для второго индекса матрицы переменную j (имена переменных для обозначения индексов могут быть и любыми другими). Тогда, если зафиксировать индекс i и изменять индекс j, матрица будет обрабатываться по строкам (быстрее изменяется второй индекс), если же зафиксировать индекс j и изменять индекс i, то матрица обрабатывается по столбцам.

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

72

Каждый циклический процесс часто требует подготовки (присвоения значения 0 для переменной, накапливающей сумму, выбора "кандидата" на максимальный элемент и т. д.). Если такая подготовка должна выполняться для каждого столбца или строки, то она выполняется перед внутренним оператором цикла. Обычно результаты обработки элементов матрицы по строкам или столбцам заносятся в массив, который объявляется вместе с матрицей и имеет соответственно размерность, равную количеству строк или столбцов.

С учетом изложенного организация операторов цикла (с использованием директив препроцессора #define для задания размерностей матрицы по строкам и столбцам) имеет формы:

При обработке матрицы по столбцам #define ROW <количество строк> #define COL <количество столбцов>

. . .

<тип> <имя_матрицы>[ROW][COL], <имя_вектора>[COL]; int i, j; // Объявление переменных для индексов матрицы for (j = 0; j < COL; j++) {

<операторы подготовки цикла обработки по столбцам> for (i = 0; i < ROW; i++) {

<операторы обработки элементов>

}

}

При обработке матрицы по строкам

#define ROW <количество строк> #define COL <количество столбцов>

. . .

<тип> <имя_матрицы>[ROW][COL], <имя_вектора>[ROW] ; int i, j; // Объявление переменных для индексов матрицы for(i = 0; i < ROW; i++)

{

<операторы подготовки цикла обработки по строкам>

73

for (j = 0; j < COL; j++)

{

<операторы обработки элементов>

}

}

Матрицу обычно вводят по строкам. Если она будет обрабатываться по строкам, то можно совместить обработку с вводом элементов матрицы. При обработке матрицы по столбцам такое совмещение (использование одних и тех же операторов цикла) невозможно. В этом случае сначала вводят матрицу, а затем ее обрабатывают. Ниже приведены примеры обработки матриц.

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

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

// Программа для подсчета сумм по столбцам матрицы.

#include "stdafx.h" #include <conio.h> #include <iostream> using namespace std; #define ROW 2 #define COL 3

void _tmain ()

{

double a[ROW][COL], b[ROW]; int i, j;

for(i = 0; i < ROW; i++)

{

cout << "Введите строку матрицы " << (i + 1) << endl; for(j = 0; j < COL; j++)

cin >> a[i][j];

}

74

for(j = 0; j < COL; j++) //‘Вычисление суммы по столбцам

{

b[j] = 0;

for(i = 0; i < ROW; i++) b[j] = b[j] + a[i][j];

}

cout <<\nСуммы по столбцам матрицы \n" << endl; for(i = 0; i < COL; i++)

cout << b[i] << " "; // Для вставки пробела между числами

_getch();

}

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

// Программа для подсчета количества нулей в строках матрицы

#include "stdafx.h" #include <conio.h> #include <iostream> using namespace std; #define ROW 2 #define COL 3

int _tmain ()

{

double a[ROW][COL];

int i, j, b[ROW]; // Количество нулей задают целым числом for (i = 0; i< ROW; i++)

{

cout << "Введите строку матрицы " << (i + 1) << endl; for (j = 0; j < COL; j++)

cin >> a[i][j];

}

75

for (i = 0; i< ROW; i++)

{

b[i] = 0; // Обнуление счетчика для каждой строки for (j = 0; j < COL; j++)

if(a[i][j] == 0) b[i]++;

}

cout <<"\nКоличества нулей по строкам матрицы\n"; for (i = 0; i< ROW; i++)

cout << b[i] << endl; // Все числа с новой строки

_getch();

}

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

Пусть имеется матрица, элементы которой имеют индексы:

a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] a[3][0] a[3][1] a[3][2] a[3][3]

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

Так, индексы у элементов, расположенных на главной диагонали, равны друг другу. Первый индекс элементов, расположенных на диагонали выше главной, меньше второго индекса и т.д.

Обрабатывать элементы, расположенные на диагонали матрицы, можно с помощью двух вложенных циклов, например, для обработки матрицы по строкам, а во внутреннем цикле с помощью оператора условного перехода if проверять соотношение между индексами. Это решение не эффективно потому, что всегда приходится просматривать n * n элементов (где n размерность матрицы), неза-

76

висимо от того, сколько элементов требуется обработать в действительности.

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

Ниже в качестве примера приведена формула для вычисления индексов на диагонали, параллельной главной и идущей сверху вниз. В этой формуле предполагается, что диагональ проходит через элемент, находящийся с края матрицы и имеющий индексы: k - номер строки, m - номер столбца. Через n обозначена размерность квадратной матрицы. Переменная i изменяется от 0 до количества элементов на диагонали. Имя матрицы matrix.

count = n - (k + m);

Выражение для индексов matrix [k + i][m + i]

Если k и m равны 0, то диагональ главная, и выражение для индексов упрощается до

matrix[i][i]

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

matrix[i][m + i]

Количество элементов для диагонали ROW - m.

77

Для элементов, расположенных ниже главной диагонали matrix[i + k][i]

Количество элементов ROW - k.

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

В некоторых случаях можно вместо формул использовать следующий прием. Пусть индексы будут обозначены переменными i и j. Тогда для каждого индекса можно ввести приращение на единицу di и dj. Ниже в таблице представлены значения приращений и их связь с перемещением по матрице.

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

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

matrix[i][m + i]

где m - номер столбца, с которого начинается диагональ, а i - текущий индекс. Для диагоналей, расположенных выше главной, начальное значение m равно 1. В примере программы размерность матрицы равна ROW или COL, поскольку матрица квадратная Коли-

78

чество элементов на диагонали выше главной равно ROW - m, а для диагоналей ниже главной длина равна ROW – n.

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

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

Для такой проверки определим в программе целочисленную переменную с именем flag. Вначале флажку присваивается некоторое значение (в данном случае 1). Во внутреннем цикле проверяется значение очередного элемента. Если значение очередного элемента матрицы не равно 0, то проверяемое в операторе if условие оказывается истинным, а значит, будет выполнен оператор flag = 0;, т.е. будет сброшен флаг.

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

// Проверка матрицы на треугольность.

#include "stdafx.h" #include <conio.h> #include <iostream> using namespace std; #define ROW 5

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]