zoukankan      html  css  js  c++  java
  • 矩阵运算

     矩阵运算 

    注意的细节1:

    二维数组在概念上是二维的,即是说其下标在两个方向上变化,下标变量在数组中的位置也处于一个平面之中,而不是象一维数组只是一个向量。但是,实际的硬件存储器却是连续编址的,也就是说存储器单元是按一维线性排列的。如何在一维存储器中存放二维数组,可有两种方式:一种是按行排列, 即放完一行之后顺次放入第二行。另一种是按列排列, 即放完一列之后再顺次放入第二列。在C语言中,二维数组是按行排列的。即,先存放a[0]行,再存放a[1]行,最后存放a[2]行。每行中有四个元素也是依次存放。由于数组a说明为int类型,该类型占两个字节的内存空间,所以每个元素均占有两个字节。

     注意的细节2:二维数组和指针的一些细节:    

    1、二维数组和数组元素的地址若有以下定义:int *p, a[3][4];

    1)二维数组a由若干个一维数组组成在C语言中定义的二维数组实际上是一个一维数组,这个一维数组的每一个成员又是一个一维数组。如以上定义的a数组,则可视a数组由a[0]、a[1]、a[2]等三个元素组成,而a[0]、a[1]、a[2]等每个元素又分别是由4个整型元素组成的一维数组。可用a[0][0]、a[0][1]等来引用a[0]中的每个元素,其它依次类推。在第二节中已解释过,C语言中,在函数体中或在函数外部定义的一维数组名是一个地址常量,其值为数组第一个元素的地址,此地址的基类型就是数组元素的类型。在以上二维数组中,a[0]、a[1]、a[2]都是一维数组名,同样也代表一个不可变的地址变量,其值依次为二维数组每行第一个元素的地址,其基类型就是数组元素的类型。因此,对于二维数组,象a[0]++这样的表达式是非法的。若有表达式a[0]+1,表达式中1的单位应当是2个字节。在以上定义中,指针变量p的基类型与a[i](0≤i<3)相同,因此,赋值语句p=a[i];是合法的。我们已知a[i]也可以写成:*(a+i),故以上赋值语句也可写成:p=*(a+i)。

    2)二维数组名也是一个地址常量二维数组名同样也是一个存放地址常量的指针,其值为二维数组中第一个元素的地址。以上a数组,数组名a的值与a[0]的值相同,只是其基类型为具有4个整型元素的数组类型。即a+0的值与a[0]的值相同,a+1的值与a[1]的值相同,a+2的值与a[2]的值相同,它们分别表示a数组中第零、第一、第二行的首地址。二维数组名应理解为一个行指针。在表达式a+1中,数值1的单位应是4×2个字节,而不是2个字节。赋值语句p=a;是不合法的,因为p和a的基类型不同。同样,对于二维数组名a,也不可以进行a++,a=a+i等运算。

    3)二维数组元素的地址二维数组元素的地址可以由表达式&a[i][j]求得;也可以通过每行的首地址来表示。以上二维数组a中,每个元素的地址可以通过每行的首地址:a[0]、a[1]、a[2]等来表示。如:地址&a[0][0]可以用a[0]+0来表示,地址&a[0][1]可以用a[0]+1表示;若0≤i<3、0≤j<4,则a[i][j]的地址可用以下五种表达式求得:(1)&a[i][j](2)a[i]+j(3)*(a+i)+j(4)&a[0][0]+4*i+j (5)a[0]+ 4*i+j

    在以上表达式中a[i]、&a[0][0]、a[0]的基类型都是int类型,系统将自动据此来确定表达式中常量1的单位是2个字节。但是不可以把求a[i][j]地址的表达式写成:a+4*i+j,因为a的基类型是4个整型元素的数组类型,系统将自动据此来确定常量1的单位是8个字节。

    2、通过地址来引用二维数组元素若有以下定义:int a[3][4],i,j;且当0≤i<3、0≤j<4,则a数组元素可用以下五种表达式来引用:(1)a[i][j](2)*(a[i]+j)(3)*(*(a+i)+j)(4)(*(a+i))[j](5)*(&a[0][0]+4*i+j)

    在(2)中,表达式*(a[i]+j)中,因为a[i]的基类型为int,j的位移量为2×j字节。在(3)中,表达式*(*(a+i)+j)中,a的基类型为4个元素的数组,i的位移量为4×2×i字节;而*(a+i)的基类型为int,j的位移量仍为2×j字节。在(4)中,*(a+i)外的一对圆括号不可少,若写成:*(a+i)[j],因为运算符[]的优先级高于*号,表达式可转换成:*(*(a+i)+j)),即为:*(*(a+i+j)),这时i+j将使得位移量为4×2×(i+j)个字节,显示然这已不是元素a[i][j]的地址。*(*(a+i+j))等价于*(a[i+j])、等价于:a[i+j][0],引用的是数组元素a[i+j][0],而不是a[i][j],很可能早已超出数组定义的范围。在(5)中,&a[0][0]+4*i+j代表了数组元素a[i][j]的地址,通过间址运算符*号,表达式*(&a[0][0]+4*i+j)代表了数组元素a[i][j]的存储单元。

    3、通过建立一个指针数组来引用二维数组元素若有以下定义:int *p[3], a[3][2], i,j ;在这里,说明符*p[3]中,也遵照运算符的优先级,一对[]的优先级高于*号,因此p首先与[]结合,构成p[3],说明了p是一个数组名,系统将为它开辟3个连续的存储单元;在它前面的*号则说明了数组p是指针类型,它的每个元素都是基类型为int的指针。若满足条件:0≤i<3,则p[i]和a[i]的基类型相同,p[i]= a[i]是合法的赋值表达式。若有以下循环:for(i=0; i<3; i++) p[i]= a[i];在这里,赋值号右边的a[i]是常量,表示a数组每行的首地址,赋值号左边的p[i]是指针变量,循环执行的结果使p[0]、p[1]、p[2]分别指向a数组每行的开头。

    当p数组的每个元素已如图9.6所示指向a数组每行的开头时,则a数组元素a[i][j]的引用形式*(a[i]+ j)和*(p[i]+j)是完全等价的。由此可见,这时可以通过指针数组p来引用a数组元素,它们的等价形式如下:(1)*(p[i]+j) (2)*(*(p+i)+j) (3)(*(p+i))[j] (4)p[i][j] 不同的是:p[i]中的值是可变的,而a[i]中的值是不可变的。

    通过建立一个行指针来引用二维数组元素若有以下定义:int a[3][2], (*prt)[2];在这里,说明符(*prt)[2]中,由于一对圆括号的存在,所以*号首先与prt结合,说明prt是一个指针变量,然后再与说明符[2]结合,说明指针变量prt的基类型是一个包含有两个int元素的数组。在这里,prt的基类型与a的相同,因此prt=a;是合法的赋值语句。prt+1等价于a+1、等价于a[1]。当prt指向a数组的开头时,可以通过以下形式来引用a[i][j]:(1) *(prt[i]+j) (2) *(*(prt+i)+j) (3)(*(prt+i))[j] (4) prt[i][j] 在这里,prt是个指针变量,它的值可变,而a是一个常量。

    矩阵的乘法:

    在C语言中注意函数里只能申明确定维数的二维数组

     1 /*
     2  * 这里需要注意的是:这里传入函数参与运算的是一维数组,而不直接传入二维数组。这是因为二维数组作为
     3  * 参数需要指定明确的行数和列数,而为了通用性,行数和列数设置为未知数。在C语言中是不允许使用变量
     4  * 作为数组的大小
     5  * 这里尝试用固定的参数定义一个二维数组,在调用时可以使用
     6  * section6_matrix::MatrixMul(a, b, m, n, k, c);
     7  * 其中a,b,c为二维数组
     8  * 缺点是通用性差
     9  */
    10 void MatrixMul(double a[3][3], double b[3][3], int m, int n, int k, double c[3][3]) {
    11     int i, j, l;
    12     double sum;
    13     for (i = 0; i < m; i++) {
    14         for (j = 0; j < k; j++) {
    15             sum = 0;
    16             for (l = 0; l < n; l++) {
    17                 sum += a[i][l] * b[l][j];
    18             }
    19             c[i][j] = sum;
    20         }
    21     }
    22 }

    C语言中函数申明的二维数组是维数是不确定的则用一维数组的方式进行申明,计算的时候需要计算具体的位置,不能简单地利用循环遍历

     1 /*
     2  * 用一维数组的方式定义二维数组,其调用方式是:
     3  * section6_matrix::MatrixMul(*a, *b, m, n, k, *c);
     4  * a,b,c为二维数组,*a,*b,*c等价于a[0],b[0],c[0],其基类型是一个double字节
     5  * 而a,b,c其基类型是一个double字节*n,n为列数
     6  */
     7 void MatrixMul(double a[],double b[],int m,int n,int k,double c[]){
     8     int i,j,l,u;
     9     for(i=0;i<m;i++){
    10         for(j=0;j<k;j++){
    11             u=k*i+j;
    12             c[u]=0.0;
    13             for(l=0;l<n;l++){
    14                 c[u]+=a[i*n+l]*b[l*k+j];
    15             }
    16         }
    17     }
    18 }

    调用矩阵乘法

     1 void runMatrixMul() {
     2     double a[3][3] = { { 1.0, 2.0, 3.0 }, { 4.0, 5.0, 6.0 }, { 7.0, 8.0, 9.0 } };
     3     double b[3][3] = { { 2.0, -2.0, 1.0 }, { 1.0, 3.0, 9.0 },
     4             { 17.0, -3.0, 7.0 } };
     5     double c[3][3];
     6     int m = 3, n = 3, k = 3, i, j;
     7     printf("The result of a * b =
    ");
     8     section6_matrix::MatrixMul(a, b, m, n, k, c);
     9     for (i = 0; i < m; i++) {
    10         for (j = 0; j < n; j++) {
    11             printf("%10.6f	", c[i][j]);
    12         }
    13         printf("
    ");
    14     }
    15 }
  • 相关阅读:
    jq 换图片路径
    sql 把一列的数据按逗号分隔转换成多行
    sql 数据库查看主外键关联
    sql 表连接 join
    sql 查看 锁定的表 或者 未提交 的事务
    WMI技术介绍和应用——查询硬件信息
    System.Web.HttpContext.Current.Server.MapPath("~/upload/SH") 未将对象引用设置为实例对象
    sql server output用法说明
    merge into 的用法
    JAVA Stop The World 第八节
  • 原文地址:https://www.cnblogs.com/hoojjack/p/5009500.html
Copyright © 2011-2022 走看看