Попробуйте часть кода до слова main заменить на #include "stdafx.h" //1 #include <iostream> //2 using namespace std; //3 |
Работа с массивами
8.3. Программирование задач линейной алгебры
8.3.1. Работа с векторами
Создание программ для обработки одномерных массивов на языках C, C++ особых проблем не вызывает. Чтобы это доказать, продемонстрируем несколько функций, реализующих стандартные операции над векторами.
Пример 8.7. Вычисление нормы вектора.
#include <stdio.h> #include <math.h> //здесь находится прототип функции sqrt #include <conio.h> double norm(double *a, int n) { double s=0; for(int i=0; i<n; i++) s += a[i]*a[i]; return sqrt(s); } void main() { double v1[5]={1.,2.,3.,4.,5.}; printf("norm=%f",norm(v1,5)); getch(); } //=== Результат работы === norm=7.416198
Функцией norm можно воспользоваться и для того, чтобы вычислить "норму" любого фрагмента вектора – достаточно вместо первого аргумента задать адрес начальной компоненты (например, &v1[2] ), а в качестве второго аргумента количество обрабатываемых компонент.
Пример 8.8. Нормирование вектора.
#include <iostream.h> #include <math.h> //здесь находится прототип функции sqrt #include <conio.h> void norm_vec(double *a, int n) { double s=0; for(int i=0; i<n; i++) s += a[i]*a[i]; s= sqrt(s); for(int i=0; i<n; i++) a[i] /= s; } void main() { double v1[5]={1.,2.,3.,4.,5.}; norm_vec(v1,5); for(int i=0;i<5;i++) cout << v1[i]<< " "; getch(); } //=== Результат работы === 0.13484 0.26968 0.40452 0.53936 0.6742
Пример 8.9. Вычисление скалярного произведения двух векторов.
#include <stdio.h> #include <conio.h> double scal_prod(double *a, double *b,int n) { double s=0; for(int i=0; i<n; i++) s += a[i]*b[i]; return s; } void main() { double v1[5]={1.,2.,3.,4.,5.}; printf("scal_prod=%f",scal_prod(v1,v1,5)); getch(); } //=== Результат работы === scal_prod=55.000000
Пример 8.10. Сумма векторов.
#include <stdio.h> #include <conio.h> void sum_vec(double *a,double *b,double *c,int n) { for(int i=0; i<n; i++) c[i]=a[i]+b[i]; } void main() { double v1[5]={1.,2.,3.,4.,5.}; double v2[5]={1.,0.,1.,0.,1.}; double v3[5]; sum_vec(v1,v2,v3,5); for(int i=0;i<5;i++) printf("%3.0f",v3[i]); getch(); } //=== Результат работы === 2 2 4 4 6
8.3.2.Работа с матрицами
Работу с двумерными массивами можно организовать двумя способами. Во-первых, операции над элементами двумерных массивов можно свести к операциям над одномерными массивами, используя приведенные индексы. Во-вторых, можно воспользоваться указателями на строки матрицы (как известно, имя массива одновременно является указателем на ее первую строку). Мы приведем примеры программ, демонстрирующие оба подхода.
Пример 8.11. Формирование единичной матрицы с приведенными индексами.
#include <stdio.h> #include <math.h> #include <conio.h> void eye(int *a, int n) { int i,j; for(i=0; i<n; i++) for(j=0; j<n;j++) { if(i==j) a[i*n+j]=1; else a[i*n+j]=0; } } void main() { int i,j,v[5][5]; eye((int*)v,5); for(i=0;i<5;i++) { for(j=0;j<5;j++) printf("%3d",v[i][j]); printf("\n"); } getch(); } //=== Результат работы
Обратите внимание на то, что при обращении к функции eye указатель v приводится к типу ( int * ). После этого указатель будет "смотреть" на элементы массива, а не на его строки.
Пример 8.12. Сложение квадратных матриц. Поскольку в операции сложения участвуют n2 одноименных компонент матриц-слагаемых, то матрицы можно рассматривать как длинные вектора и производить сложение как с векторами:
#include <stdio.h> #include <math.h> #include <conio.h> void add_mat(int *a,int *b,int *c,int n) { int i; for(i=0; i<n*n; i++) c[i]=a[i]+b[i]; } void main() { int i,j,v3[3][3]; int v1[3][3]={{1,2,3},{4,5,6},{7,8,9}}; int v2[3][3]={{0,0,1},{0,0,2},{0,0,3}}; add_mat((int*)v1,(int*)v2,(int*)v3,3); for(i=0;i<3;i++) { for(j=0;j<3;j++) printf("%3d",v3[i][j]); printf("\n"); } getch(); } //=== Результат работы ===
Пример 8.13.Умножение квадратных матриц с использованием приведенных индексов.
#include <stdio.h> #include <conio.h> void mult_mat(int *a,int *b,int *c,int n) { int i,j,k,s; for(i=0; i<n; i++) for(j=0; j<n;j++) { s=0; for(k=0;k<n;k++) s += a[i*n+k]*b[k*n+j]; //s=s+ai,k*bk,j c[i*n+j]=s; //ci,j=s } } void main() { int i,j,v3[2][2]; int v1[2][2]={{1,2},{3,4}}; int v2[2][2]={{5,6},{7,8}}; mult_mat((int*)v1,(int*)v2,(int*)v3,2); for(i=0;i<2;i++) { for(j=0;j<2;j++) printf("%4d",v3[i][j]); printf("\n"); } getch(); } //=== Результат работы ===
Пример 8.14. Транспонирование матрицы с использованием массива указателей на строки.
#include <stdio.h> #include <conio.h> void transp(int *p[],int n) { int tmp,i,j; for(i=0; i<n-1; i++) for(j=i+1; j<n; j++) { tmp=p[i][j]; p[i][j]=p[j][i]; p[j][i]=tmp; } } void main() { int v[4][4]={{ 1, 2, 3, 4}, { 5, 6, 7, 8}, { 9,10,11,12}, {13,14,15,16}}; //массив указателей на строки int *p[4]={(int *)&v[0],(int *)&v[1],(int *)&v[2],(int *)&v[3]}; transp(p,4); for(int i=0; i<4; i++) { for(int j=0;j<4;j++) printf("%3d",v[i][j]); printf("\n"); } getch(); } //=== Результат работы ===
Массив указателей p на строки двумерного массива v может быть сформирован и другими способами:
int *p[4]={(int *)v,(int *)(v+1),(int *)(v+2),(int *)(v+3)}; int *p[4]={v[0],v[1],v[2],v[3]}; int *p[4]={*v,*(v+1),*(v+2),*(v+3)};
Очевидно, что указатель p[0] "смотрит" на элемент v[0][0]. Поэтому указатель p[0][1]=p[0]+1 "смотрит" на элемент v[0][1], указатель p[0][2] – на элемент v[0][2] и т.д. Можно было бы видоизменить заголовок функции transp следующим образом:
void transp(int **p,int n)
Все эти модификации ничего не меняют в алгоритмах работы программ.