有效地存储三角矩阵

时间:2014-12-09 13:25:50

标签: c arrays memory-management matrix-multiplication triangular

我需要通过不将所有零存储在内存中来有效地存储下三角矩阵,所以我已经考虑过这种方式:首先我为每一行分配内存,然后为每一行分配i + 1个字节,所以我永远不必担心零,但在第一次分配时出现问题。我究竟做错了什么?这是我的代码,编译器在读取矩阵的维度后,在第8行退出程序。

#include <stdio.h>
#include <stdlib.h>

int main ()
{
  int i, j, **mat1, dim;

  scanf("%d",&dim);
  *mat1 = (int**)calloc(dim, sizeof(int*));

  for(i = 0; i<dim; i++)
    mat1[i] = (int*)calloc(i+1, sizeof(int));

  for(i = 0; i < dim; i++)
    for(j = 0; j < i+1; j++)
       scanf("%d", &mat1[i][j]);

  for(i=0; i<dim; i++)
    for(j=0; j<(i+1); j++)
       printf("%d%c", mat1[i][j], j != (dim-1) ? ' ' : '\n');

  return 0;
}

修改

好的,所以在按照你帮助我的方式修改代码之后,我必须阅读一个上三角和下三角矩阵并显示他们的产品。这个问题是我没有将零存储在内存中,所以如果我使用传统的3-for算法,它会显示一些垃圾值。如果我用0初始化每个矩阵的其余部分,动态分配内存是没用的,因为我也会存储零,所以我还没有完成任何提高存储效率的东西。我想我必须在某处修改代码,或者可能是间隔,但无论如何我修改程序仍然输出(对于3x3矩阵)右上角的2个垃圾值。我怎么能这样做?

#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i,j,k,**mat1,**mat2,**prod,dim;


printf("Give dimension: \n");
scanf("%d",&dim);

mat1 = (int**)calloc(dim,sizeof(int*));

for(i=0; i<dim; i++)
    mat1[i] = (int*)calloc(i+1,sizeof(int));

mat2 = (int**)calloc(dim,sizeof(int*));

for(i=dim-1; i>-1; i--)
    mat2[i]=(int*)calloc(i+1,sizeof(int));

prod = (int**)calloc(dim,sizeof(int*));
for(i=0; i<dim; i++)
    prod[i] = (int*)calloc(dim,sizeof(int));

printf("Give lower triangular matrix(non 0 values only): \n");
for(i=0; i<dim; i++)
    for(j=0; j<i+1; j++)
        scanf("%d",&mat1[i][j]);

printf("Give upper triangular matrix(non 0 values): \n");
for(i=0; i<dim; i++)
    for(j=i; j<dim;j++)
        scanf("%d",&mat2[i][j]);

printf("Matrix A is: \n");
for(i=0; i<dim; i++)
    for(j=0; j<dim; j++)
        printf("%d%c",j<=i?mat1[i][j]:0,j!=dim-1?' ':'\n');

printf("Matrix B is: \n");
for(i=0; i<dim; i++)
    for(j=0; j<dim; j++)
        printf("%d%c",j>=i?mat2[i][j]:0,j!=dim-1?' ':'\n');

for(i=0; i<dim; i++)
    for(j=0; j<dim; j++)
        for(k=0; k<dim; k++)
            prod[i][j]+=mat1[i][k]*mat2[k][j];


printf("The product of the two matrix is: \n");
for(i=0; i<dim; i++)
    for(j=0; j<dim; j++)
        printf("%d%c",prod[i][j],j!=dim-1?' ':'\n');


return 0;

}

3 个答案:

答案 0 :(得分:7)

如果你想节省空间和分配矩阵的每一行的开销,你可以通过巧妙地索引单个数组来实现三角矩阵。

下三角矩阵(包括对角线)具有以下属性:

Dimension   Matrix    Elements/row   Total elements
1           x . . .   1              1
2           x x . .   2              3
3           x x x .   3              6
4           x x x x   4              10
...

给定维度的元素总数为:

size(d) = 1 + 2 + 3 + ... + d  =  (d+1)(d/2)

如果在一个数组中连续排列行,可以使用上面的公式计算矩阵内给定行和列的偏移量(均为零):

index(r,c) = size(r-1) + c

上面的公式适用于下三角矩阵。您可以通过简单地反转索引来访问上部矩阵,就像它是一个较低的矩阵一样:

index((d-1)-r, (d-1)-c)

如果您担心更改数组的方向,可以为上部数组设计不同的偏移计算,例如:

uindex(r,c) = size(d)-size(d-r) + c-r

示例代码:

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#define TRM_SIZE(dim) (((dim)*(dim+1))/2)
#define TRM_OFFSET(r,c) (TRM_SIZE((r)-1)+(c))
#define TRM_INDEX(m,r,c) ((r)<(c) ? 0 : (m)[TRM_OFFSET((r),(c))])
#define TRM_UINDEX(m,r,c,d) ((r)>(c)?0:(m)[TRM_SIZE(d)-TRM_SIZE((d)-(r))+(c)-(r)])
#define UMACRO 0


int main (void)
{
  int i, j, k, dimension;
  int *ml, *mu, *mr;

  printf ("Enter dimension: ");
  if (!scanf ("%2d", &dimension)) {
    return 1;
  }

  ml = calloc (TRM_SIZE(dimension), sizeof *ml);
  mu = calloc (TRM_SIZE(dimension), sizeof *mu);
  mr = calloc (dimension*dimension, sizeof *mr);
  if (!ml || !mu || !mr) {
    free (ml);
    free (mu);
    free (mr);
    return 2;
  }

  /* Initialization */

  srand (time (0));
  for (i = 0; i < TRM_SIZE(dimension); i++) {
    ml[i] = 100.0*rand() / RAND_MAX;
    mu[i] = 100.0*rand() / RAND_MAX;
  }

  /* Multiplication */

  for (i = 0; i < dimension; i++) {
    for (j = 0; j < dimension; j++) {
      for (k = 0; k < dimension; k++) {
        mr[i*dimension + j] +=
#if UMACRO
          TRM_INDEX(ml, i, k) *
          TRM_UINDEX(mu, k, j, dimension);
#else
          TRM_INDEX(ml, i, k) *
          TRM_INDEX(mu, dimension-1-k, dimension-1-j);
#endif
      }
    }
  }

  /* Output */

  puts ("Lower array");
  for (i = 0; i < dimension; i++) {
    for (j = 0; j < dimension; j++) {
      printf (" %2d", TRM_INDEX(ml, i, j));
    }
    putchar ('\n');
  }
  puts ("Upper array");
  for (i = 0; i < dimension; i++) {
    for (j = 0; j < dimension; j++) {
#if UMACRO
      printf (" %2d", TRM_UINDEX(mu, i, j, dimension));
#else
      printf (" %2d", TRM_INDEX(mu, dimension-1-i, dimension-1-j));
#endif
    }
    putchar ('\n');
  }
  puts ("Result");
  for (i = 0; i < dimension; i++) {
    for (j = 0; j < dimension; j++) {
      printf (" %5d", mr[i*dimension + j]);
    }
    putchar ('\n');
  }

  free (mu);
  free (ml);
  free (mr);

  return 0;
}

请注意,这是一个简单的例子。您可以扩展它以将矩阵指针包装在一个结构中,该结构还存储矩阵的类型(上下三角形或正方形)和尺寸,以及根据矩阵类型适当操作的写访问函数。

对于任何非平凡的矩阵使用,您应该使用专门研究矩阵的第三方库。

答案 1 :(得分:3)

mat1 = calloc(dim,sizeof(int*));

mat1是一个双指针。你需要为你的指针数组分配内存,之后你需要单独为你的每个指针分配内存。不需要转换calloc()

答案 2 :(得分:1)

您在第8行取消引用 mat1 ,然后才将其设置为指向任意位置。你正在为int分配一个指针数组,但是你没有将它指定给 mat1 ,而是指向mat1的取消引用,这是未初始化的,我们不知道它指向的是什么。

所以这一行:

// ERROR: You are saying an unknown memory location should have the value of calloc.
*mat1 = (int**)calloc(dim,sizeof(int*));

应改为:

// OK: Now you are assigning the allocation to the pointer variable.
mat1 = (int**)calloc(dim,sizeof(int*));