Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Матрицы, указатели и функции



Пусть объявлена статическая матрица const n=6, m=10; int M[n][m];. Этим самым мы объявили не один, а n константных указателей:

M[0] или &M[0][0] – адрес начала 0 -й строки,

M[1] или &M[1][0] – адрес начала 1 -й строки, и т. д.,

M[n-1] или &M[n-1][0] – адрес начала (n-1) -й строки.

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

float *q; int n1=2, n2=4; q=M[n1];

M[n1]=M[n2]; /* Ошибка! */ M[n2]=q; // Ошибка!

Если первое присваивание правильно, то второе и третье присваивания ошибочны, так как каждый из константных указателей (M[i] и M[j]) нельзя использовать слева в операторе присваивания. Позже будет показано, как такие перестановки строк сделать, используя вспомогательный массив указателей.

Преимуществом языка С++ по сравнению с другими языками является следующая удобная для практического использования возможность. Функцию обработки одномерного массива можно использовать при работе с частью матрицы. Пусть отлажена функция сортировки одномерного массива с таким, например, прототипом void Fun1 (int *x, int k); где x — адрес одномерного массива, n — его размерность. Такую функцию можно использовать не только для работы с одномерным массивом. Можно передать в качестве фактического параметра адрес какого-нибудь элемента матрицы. Рассмотрим следующие фрагменты программ.

1) for (int i=0; i<n; i++) Fun1 (M[i], m, …);

независимаясортировка всех m элементов каждой строки.Это же можно записать и так: for (int i=0; i<n; i++) Fun1 (&M[i][0], m, …); В качестве фактического параметра передаём адрес начала i -й строки матрицы и количество участвующих в сортировке элементов, то есть всю строку.

2) for (int i=0; i<n; i+=2) Fun1 (M[i], 2*m, …);

сначала сортируется 0-я и 1-я строки матрицы вместе как один одномерный массив размерности 2*m. Затем аналогично сортируем 2-ю и 3-ю строки и т. д., и, наконец, (n-2)- ю и (n-1)- ю строки. При этом существенно используется то, что элементы статической матрицы в памяти располагаются непрерывно по строкам. После последнего элемента i- й строки следует первый элемент следующей (i+1)- й строки. Заметим, что этот цикл будет правильно работать, если в матрице чётное количество строк. В качестве упражнения внести изменения в предыдущий фрагмент, чтобы он работал и для нечётного n.

3) for (int i=0; i<n; i++) Fun1 (&M[i][m/2], m/2, …);

— в каждойстроке матрицы в сортировке участвуют последние m/2 элементов строки. Предполагается, что m — чётное. В качестве упражнения внести изменения в этот фрагмент таким образом, чтобы в случае, если m — нечётное, сортировались последние m/2+1 элементов строки. Например, если m=15, должны сортироваться последние 8 элементов.

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

Пусть описана функция: int MyFun2 (int *x, int k); в которой по некоторому алгоритму для одномерного массива x размерности k получаем и возвращаем некоторый параметр (например, сумму положительных чисел) в виде одного целого числа. Как эту функцию использовать для получения и (или) вывода этого же параметра для всей матрицы (одного целого числа), объявленной в начале параграфа? Выберите правильные варианты ответов:

1) int Res=MyFun2 (&A[0][0], n); cout<<Res;

2) int Res=MyFun2 (A[0], m); cout<<Res;

3) int Res=MyFun2 (A[0], m*n); cout<<Res;

4) cout<< MyFun2 (&A[0][0], n*m);

Решение. В первом варианте будет обработано 4 первых (из шести) числа первой с 0-м номером строки матрицы. Так как &A[0][0] и A[0] для матрицы — это адрес её начала, то есть адрес элемента A[0][0], то во втором варианте будут проанализированы m=6 элементов той же первой с 0-м номером строки матрицы. Правильными будут третий и четвёртый варианты, в которых найденный в функции параметр будет получен для m*n элементов матрицы, начиная с A[0][0], то есть с самого начала матрицы. Заметим, что так как второй параметр функции — это целое число, то m*n и n*m — это одно и то же значение, то есть общее количество элементов матрицы.

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

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

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

Есть два варианта объявления матрицы в скобках в заголовке функции. Пусть объявлены две глобальные константы: const n=5, m=10;

Вариант 1. С помощью явных или предварительно объявленных глобальных констант в матрице, записываемой в качестве параметра функции, указываем обе размерности: void FunMatr11(int M[n][m], …);. В этом варианте обрабатываем все (у нас 5) строки. Можно через параметр (size1) передать меньшее их количество: void FunMatr12(int M[n][m], short size1, …);.

Во втором варианте первую левую размерность можно оставить свободной, записав пустые квадратные скобки. При этом количество столбцов обязательно указываем: void FunMatr21(int M[][m], int size1, …); В этом способе, как правило, передаётся в качестве параметра и количество строк (size1), которое используется в соответствующих циклах.

В обоих вариантах в функции необязательно обрабатывать указанное количество столбцов (у нас m=10). Его, как и первую размерность, можно также передать в качестве параметра (size2) и затем использовать в теле функции:

void FunMatr(int M[][m], int size1, int size2,…);.

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

В вызываемой функции (у нас в main) объявляем матрицу int A[n][m]; учитывая следующее ограничение: количество столбцов при объявлении должно быть точно таким, как и в заголовке функции. Количество строк может быть меньше, чем в заголовке, например, int B[3][m]: При вызове функции в любом случае указываем только имя матрицы без указания размерности и типа её элементов и, если надо, реальное количество строк и столбцов:

FunMatr11(A, …); FunMatr12(A, n, …);

FunMatr12(A, 3, …); FunMatr12(B, 3, …);

FunMatr12(B, 2, …); FunMatr2 (A, 3, …);

FunMatr (A, 3, 6, …);

Во всех вариантах n, 3, 2 — реальное количество обрабатываемых строк, 6 — реальное количество обрабатываемых столбцов.

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

1. Функция анализирует или получает одно число. Как такую функцию использовать для каждого элемента матрицы?

2. Параметром функции является одномерный массив, который в ней анализируется, получается или преобразуется. Как её использовать для каждой строки матрицы, для части строки, для нескольких соседних строк или для всей матрицы?

3. Функция работает со всей матрицей.

Пример 20. Составим функции для ввода(INP1), вывода матрицы (OUT1) и сортировки строк по элементам k –го столбца (SORT1), где k передаём как параметр функции. При сортировке строки переставляются местами, а порядок элементов каждой строки не меняется. Пример показывает, как передать всю матрицу в функцию.

const m2=3; /* Глобальная константа */

void INP1(int x[][m2], int);

void OUT1(int x[][m2], int);

void SORT1(int x[][m2], int, int);

main()

{const n=5; int a[n][m2], k; INP1(a,n);

cout<<"\nOld matrix\n"; OUT1(a,n);

cout <<"\n The number of collumn ";

/* Ввод номера столбца с контролем ввода * /

while(1) { cin>>k; if (k>=0 && k<m2) break;

cout<<"k>=0 && k<"<<m2<<" Repeat "; }

SORT1(a,n,k); cout<<"\nMatrix after sorting\n"; OUT1(a,n);

getch(); return 0; }

/* Для сортировки используется алгоритм выбора минимального элемента */

void SORT1(int x[][m2], int size1, int k)

{ int i,j,ind,mn,N;

for (ind=0;ind<size1-1;ind++)

{ mn=x[ind][k]; N=ind;

/* Поиск в k -м столбце минимального элемента (mn), начиная с элемента с номером ind, и его номера (N). */

for (i=ind+1;i<size1;i++)

if (x[i][k]<mn) { mn=x[i][k]; N=i; }

/* Перестановка N -й строки со строкой ind. */

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

{ int t=x[ind][j]; x[ind][j]=x[N][j];

x[N][j]=t; } // The end of for (j …)

} // The end of for (i…)

} // The end of funcion SORT1

void INP1(int x[][m2],int size1)

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

for (int j=0; j<m2; j++) x[i][j]=random(20)-10; }

void OUT1(int x[][m2], int size1)

{ int X,j,Y=wherey();

for (int i=0; i<size1; i++, Y++)

for (X=1, j=0; j<m2; j++, X+=7) { gotoxy(X,Y); cout<<x[i][j]; }

cout<<endl;

}

Пример 21. Составим следующие функции. Первая (InpMatr) вводит матрицу оценок по десятибалльной системе с контролем ввода. Если наберём при вводе число, меньше единицы или больше десяти, то программа даёт возможность повторить ввод этого же элемента матрицы без изменения индексов. Вторая функция MyOutCol выводит матрицу разным цветом. Строки, в которых есть хотя бы одна плохая оценка (1, 2 или 3) выделяем одним цветом, а остальные строки выводим другим цветом. Вспомогательная функция Inp1 с позиции с текстовыми координатами (x0, y0) вводит одну оценку с контролем ввода и используется в InpMatr для ввода каждого элемента матрицы. Функция Test возвращает true, еслив одномерном массиве есть хотя бы одна плохая оценка 1, 2 или 3, и false в противном случаe. Эта функция используется в MyOutCol для анализа каждой строки матрицы, а в main с её помощью анализируем всю матрицу. В функции MyOutCol два параметра цвета по умолчанию.

const m=5;

void Inp1(int x0, int y0, unsigned short &b)

{ /* Цикл для ввода одного числа с контролем ввода */

while (1) { gotoxy(x0,y0); cin>>b;

if (b>=1 && b<=10) return;

else { gotoxy(x0,y0); cout<<" "; }

} // The end of while

} // The end of funcion Inp1

void InpMatr (unsigned short a[][m], int);

bool Test(unsigned short *a1, int =m);

void MyOutCol (unsigned short a[][m], int, int =12, int=10);

int main() { const n=4; unsigned short A[n][m];

InpMatr(A, n); MyOutCol(A,n);

if (Test(A[0],n*m)) cout<<"\nYes"; else cout<<"\nNo";

getch(); return 0; }

void InpMatr (unsigned short a[][m], int size1)

{ int x, y, i, j;

for(y=wherey()+1, i=0; i< size1; i++, y++)

for(x=1, j=0; j<m; j++, x+=6) Inp1(x,y,a[i][j]); }

bool Test(unsigned short *a1, int size2)

{ for(int j=0; j<size2; j++) if (a1[j]<=3) return 1;

return 0; }

void MyOutCol

(unsigned short a[][m], int size1, int c1, int c2)

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

{ cout<<endl; /* Устанавливаем цвет для i – строки */

if (Test(a[i],m)) textcolor(c1); else textcolor(c2);

/* Вывод i – строки */

for(int j=0; j<m; j++)

cprintf("%5d", a[i][j]);

} // The end of for(i …)

} // The end of function MyOutCol

Пример 22. Ту же задачу (см. прим. 20) решим с помощью методов класса.

При работе со статической матрицей в методах класса матрица объявляется в классе в качестве поля с максимальными первой и второй размерностями, в качестве которых можно использовать глобальные константы (n1max и n2max). Реальное количество строк и столбцов также объявляем, как два поля класса (size1 и size2), и определяем их с помощью конструктора. Желательно в нём предусмотреть проверку, не превосходят ли реальные размерности матриц их наибольшие значения. В методах класса матрица и её размерности в качестве параметров не записываются. Значения элементов матрицы определяются одним из описанных в § 1 способов (вводятся с помощью метода INP1).

const unsigned n1max=5, n2max=10;

class MatrClass

{ double x[n1max][n2max]; unsigned size1, size2;

public:

MatrClass (unsigned n1, unsigned n2)

{ if (n1<=0 || n1>n1max) n1=n1max;

if (n2<=0 || n2>n2max) n2=n2max;

size1=n1; size2=n2; }

void INP1(); void OUT1(); void SORT1(int);

}; // End of class

void MatrClass::INP1()

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

for (int j=0; j<size2; j++) x[i][j]=random(20)-10; }

void MatrClass::SORT1(int k)

{ int i,j,m,mn,N;

for (m=0;m<size1-1;m++) { mn=x[m][k]; N=m;

for (i=m+1; i<size1; i++)

if (x[i][k]<mn) { mn=x[i][k]; N=i; }

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

{ double t=x[m][j]; x[m][j]=x[N][j]; x[N][j]=t; } }

}

void MatrClass::OUT1()

{ int X,j,Y=wherey();

for (int i=0; i<size1; i++, Y++)

for (X=1, j=0; j<size2; j++, X+=7) { gotoxy(X,Y); cout<<x[i][j]; }

cout<<endl; }

int main() { const N1=3, N2=6; int k;

MatrClass ObjMatr (N1, N2);

ObjMatr.INP1();

cout<<"\nOld matrix\n"; ObjMatr.OUT1();

cout <<"\n Тhe number of collumn =>";

/* Ввод с контролем номера столбца, по которому будем сортировать */

while(1) { cin>>k; if (k>=0 && k<N2) break;

cout<<"k>=0 && k<"<<N2<<" Repeat "; }

ObjMatr.SORT1(k); cout<<"\n After sorting\n";

ObjMatr.OUT1();

getch(); return 0; }





Дата публикования: 2015-02-18; Прочитано: 270 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.023 с)...