Нижегородский государственный университет им. Н.И.Лобачевского
Опубликован: 25.11.2008 | Доступ: свободный | Студентов: 9592 / 1296 | Оценка: 4.06 / 3.66 | Длительность: 21:16:00
Лекция 9:

Работа с массивами

< Лекция 8 || Лекция 9: 12345 || Лекция 10 >

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)

Все эти модификации ничего не меняют в алгоритмах работы программ.

< Лекция 8 || Лекция 9: 12345 || Лекция 10 >
Alexey Ku
Alexey Ku

Попробуйте часть кода до слова main заменить на 

#include "stdafx.h" //1

#include <iostream> //2
#include <conio.h>

using namespace std; //3

Александр Талеев
Александр Талеев

#include <iostream.h>
#include <conio.h>
int main(void)
{
int a,b,max;
cout << "a=5";
cin >> a;
cout <<"b=3";
cin >> b;
if(a>b) max=a;
else max=b;
cout <<" max="<<max;
getch();
return 0;
}

при запуске в visual express выдает ошибки 

Ошибка    1    error C1083: Не удается открыть файл включение: iostream.h: No such file or directory    c:\users\саня\documents\visual studio 2012\projects\проект3\проект3\исходный код.cpp    1    1    Проект3

    2    IntelliSense: не удается открыть источник файл "iostream.h"    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    1    1    Проект3

    3    IntelliSense: идентификатор "cout" не определен    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    6    1    Проект3

    4    IntelliSense: идентификатор "cin" не определен    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    7    1    Проект3

при создании файла я выбрал пустой проект. Может нужно было выбрать консольное приложение?