您的位置:首页 > 理论基础 > 数据结构算法

28、数据结构笔记之二十八数组之矩阵

2017-09-20 21:27 465 查看
28、数据结构笔记之二十八数组之矩阵
“在命运的颠沛中,最可以看出人们的气节。 --
莎士比亚”


上篇咱们看了数组的一些定义和概念,接下去我们来看下数据和矩阵。

 

 

1.  特殊矩阵

二维数组可以来存储矩阵元素。有的程序设计语言中还供了各种矩阵运算,给用户使用带来很大的方便。然而,在数值分析中经常出现一些高阶矩阵,在这些高阶矩阵中有许多值相同的元素或者是零元素,为了节省存储空间对这类矩阵采用多个值  相同的元素只分配一个存储空间,有时零元素不存储的存储策略,称为矩阵的压缩存储。

 

如果值相同的元素或者零元素在矩阵中的分布有一定规律,称此类矩阵为特殊矩阵,反之称为稀疏矩阵。

 

1.1      对称矩阵

若一个n阶矩阵的主满足aij=aj i  1≤i,j≤n,则称该矩阵为n阶对称矩阵。

由于对称矩阵有上述性质,可以为每一对对称元分配一个存储空间,这样就将n2个元的存储空间压缩成n(n+1)/2个单元的存储空间,以行序为主序存储对称矩阵的下三角(包括对角线)的元素。

 

1.2      三角矩阵

三角矩阵分上三角矩阵和下三角矩阵两种。上三角矩阵的对角线左下方的系数全部为零,下三角矩阵的对角线右上方的系数全部为零。三角矩阵可以看做是一般方阵的一种简化情形。

 

1.3      对角矩阵

对角矩阵(diagonalmatrix)是一个主对角线之外的元素皆为 0 的矩阵。对角线上的元素可以为 0或其他值。

 

 

2.  稀疏矩阵

矩阵中非零元素的个数远远小于矩阵元素的总数,并且非零元素的分布没有规律,则称该矩阵为稀疏矩阵(sparsematrix);与之相区别的是,如果非零元素的分布存在规律(如上三角矩阵、下三角矩阵、对称矩阵),则称该矩阵为特殊矩阵。

人们无法给出确切的定义,它只是一个凭人们的直觉来了解的概念。假设在m×n的矩阵中,有t个非零元素,若t远远小于矩阵元素的总数(即t<<m×n),则称A为稀疏矩阵。

精确点,设在矩阵A中,有t个非零元素。令,称δ为矩阵的稀疏因子。通常认为δ≤0.05时称之为稀疏矩阵。

 

2.1      稀疏矩阵存储

在存储稀疏矩阵时,为了节省存储单元,很自然地想到使用压缩存储方法。

2.1.1          三元组

但由于非零元素的分布一般是没有规律的,因此在存储非零元素的同时,还必须同时记下它所在的行和列的位置(i,j)。反之,一个三元组(i,j,aij)唯一确定了矩阵A的一个非零元。因此,稀疏矩阵可由表示非零元的三元组及其行列数唯一确定。比如(1,2,3)和(3,2,1)就是两个不同的有序三元组.

2.1.2          行逻辑链接顺序表

方法在三元组顺序表的基础上,增加一个数组存储矩阵中每行第一个非0元素出现的位置。

2.1.3          十字链表

十字链表表示稀疏矩阵比较复杂。具体查看《18、数据结构笔记之十八链表实现稀疏矩阵》

 

 

3.  特殊矩阵压缩存储

主要考虑的是对称矩阵,三角矩阵及三对角矩阵的一些操作。

3.1      定义

定义了如下全局变量

//矩阵的压缩存储
int TA[MaxN],TC[MaxN];
int n;
int A[MaxN][MaxN],B[MaxN][MaxN]; 

 

 

3.2      Value

输入要操作的对称矩阵阶数。

输入每个矩阵中的每个数。只接受一半的数字输入即可。

然后通过循环实现另一半的数字录入。

然后输出矩阵。

最后将矩阵输入到一个数组中,并进行输出。

void value()
{
  inti,j,k;
  printf("请输入要操作的对称矩阵的阶数:");
  scanf("%d",&n);
 
  printf("输入对称矩阵:");
    for(i=1;i<=n;i++)
        for(j=i;j<=n;j++)
           scanf("%d",&A[i][j]);
                     for(i=1;i<=n;i++)
                     {
                               
for(j=1;j<=n;j++)
                                {
                                         
if(i>j)  A[i][j]=A[j][i];
                                         
else  A[i][j]=A[i][j];
                                }
                     }
                     printf("输出对称矩阵:\n");
                     for(i=1;i<=n;i++)
                     {
                               
for(j=1;j<=n;j++)
                                          printf("%-4d",A[i][j]);
                                printf("\n");
                     }
                    
                     k=0;
                     for(i=1;i<=n;i++)          
                               
for(j=1;j<=n;j++)
                                          TA[k++]=A[i][j];
                                printf("压缩后的对称矩阵:\n");
                               
for(k=0;k<=n*n-1;k++)
                                          printf("%-4d",TA[k]);
                                printf("\n");
}

 

 

 

3.3      Sfdg

输入上三角矩阵的阶数,然后输入数字,只取行数大于列数的数字。其他值为0.

然后进行输出,最后复制给数组进行输出。

void sfdg()
{
  inti,j,k;
  printf("请输入要操作的上三角矩阵的阶数:");
  scanf("%d",&n);
 
  printf("输入上三角矩阵:");
  for(i=1;i<=n;i++)
  {
             for(j=1;j<=n;j++)
             {
                       if(i>j)  A[i][j]=0;
                       else  scanf("%d",&A[i][j]);
             }
  }
  printf("输出上三角矩阵:\n");
  for(i=1;i<=n;i++)
  {
             for(j=1;j<=n;j++)
                       printf("%-4d",A[i][j]);
             printf("\n");
  }
 
  k=0;
  for(i=1;i<=n;i++)      

             for(j=1;j<=n;j++)
                       TA[k++]=A[i][j];
             printf("压缩后的上三角矩阵:\n");
             for(k=0;k<=n*n-1;k++)
                       printf("%-4d",TA[k]);
             printf("\n");
}

 

3.4      Sfvd

下三角同理。

3.5      Store

输入三对角矩阵的阶数。

存储3条主对角线上的数字,然后保存输出。

void store()
{
  inti,j,k;
  printf("请输入要操作的三对角矩阵的阶数:");
  scanf("%d",&n);
 
  printf("输入三对角矩阵:");
  for(i=1;i<=n;i++)
  {
             if(i==1)
             {
                       for(j=1;j<=2;j++)
                                  scanf("%d",&A[i][j]);
             }
             elseif(i>1&&i<n)
             {
                       for(j=i-1;j<=i+1;j++)
                                  scanf("%d",&A[i][j]);
             }
             elseif(i=n)
             {
                       for(j=i-1;j<=i;j++)
                                  scanf("%d",&A[i][j]);
             }
  }
  printf("输出三对角矩阵:\n");
    for(i=1;i<=n;i++)
           {
        for(j=1;j<=n;j++)
                                printf("%-4d",A[i][j]);
                     printf("\n");
           }
          
           k=0;
           for(i=1;i<=n;i++)          
                     for(j=1;j<=n;j++)
                               
if(A[i][j]!=0) 

                                          TA[k++]=A[i][j];
                                printf("压缩后的三对角矩阵:\n");
                               
for(k=0;k<=n*n-1;k++)
                                          printf("%-4d",TA[k]);
}

3.6      Add

输入三对角矩阵阶数,先输入A

然后输入矩阵B。

 

 

 

 

3.7      menu_list

只是个菜单,详见源码部分。

3.8      Main函数

Main函数实现主菜单函数的调用,然后根据输入数字调用不同的函数。

           如下图1:

 

 

3.9      源码

#include<stdio.h>
#include<stdlib.h>
#defineMaxN100
 
//矩阵的压缩存储
int TA[MaxN],TC[MaxN];
int n;
int A[MaxN][MaxN],B[MaxN][MaxN]; 

void value()
{
  inti,j,k;
  printf("请输入要操作的对称矩阵的阶数:");
  scanf("%d",&n);
 
  printf("输入对称矩阵:");
    for(i=1;i<=n;i++)
        for(j=i;j<=n;j++)
           scanf("%d",&A[i][j]);
                     for(i=1;i<=n;i++)
                     {
                               
for(j=1;j<=n;j++)
                                {
                                         
if(i>j)  A[i][j]=A[j][i];
                                         
else  A[i][j]=A[i][j];
                                }
                     }
                     printf("输出对称矩阵:\n");
                     for(i=1;i<=n;i++)
                     {
                               
for(j=1;j<=n;j++)
                                          printf("%-4d",A[i][j]);
                                printf("\n");
                     }
                    
                     k=0;
                     for(i=1;i<=n;i++)          
                               
for(j=1;j<=n;j++)
                                          TA[k++]=A[i][j];
                                printf("压缩后的对称矩阵:\n");
                               
for(k=0;k<=n*n-1;k++)
                                          printf("%-4d",TA[k]);
                                printf("\n");
}
 
void sfdg()
{
  inti,j,k;
  printf("请输入要操作的上三角矩阵的阶数:");
  scanf("%d",&n);
 
  printf("输入上三角矩阵:");
  for(i=1;i<=n;i++)
  {
             for(j=1;j<=n;j++)
             {
                       if(i>j)  A[i][j]=0;
                       else  scanf("%d",&A[i][j]);
             }
  }
  printf("输出上三角矩阵:\n");
  for(i=1;i<=n;i++)
  {
             for(j=1;j<=n;j++)
                       printf("%-4d",A[i][j]);
             printf("\n");
  }
 
  k=0;
  for(i=1;i<=n;i++)      

             for(j=1;j<=n;j++)
                       TA[k++]=A[i][j];
             printf("压缩后的上三角矩阵:\n");
             for(k=0;k<=n*n-1;k++)
                       printf("%-4d",TA[k]);
             printf("\n");
}
 
void sfvd()
{
  inti,j,k;
  printf("请输入要操作的下三角矩阵的阶数:");
  scanf("%d",&n);
 
  printf("输入下三角矩阵:");
  for(i=1;i<=n;i++)
  {
             for(j=1;j<=n;j++)
             {
                       if(i>=j)  scanf("%d",&A[i][j]);
                       else  A[i][j]=0;
             }
  }
  printf("输出下三角矩阵:\n");
  for(i=1;i<=n;i++)
  {
             for(j=1;j<=n;j++)
                       printf("%-4d",A[i][j]);
             printf("\n");
  }
 
  k=0;
  for(i=1;i<=n;i++)
             for(j=1;j<=n;j++)
                       TA[k++]=A[i][j];
             printf("压缩后的下三角矩阵:\n");
             for(k=0;k<=n*n-1;k++)
                       printf("%-4d",TA[k]);
             printf("\n");
}
 
void store()
{
  inti,j,k;
  printf("请输入要操作的三对角矩阵的阶数:");
  scanf("%d",&n);
 
  printf("输入三对角矩阵:");
  for(i=1;i<=n;i++)
  {
             if(i==1)
             {
                       for(j=1;j<=2;j++)
                                  scanf("%d",&A[i][j]);
             }
             elseif(i>1&&i<n)
             {
                       for(j=i-1;j<=i+1;j++)
                                  scanf("%d",&A[i][j]);
             }
             elseif(i=n)
             {
                       for(j=i-1;j<=i;j++)
                                  scanf("%d",&A[i][j]);
             }
  }
  printf("输出三对角矩阵:\n");
    for(i=1;i<=n;i++)
           {
        for(j=1;j<=n;j++)
                                printf("%-4d",A[i][j]);
                     printf("\n");
           }
          
           k=0;
           for(i=1;i<=n;i++)          
                     for(j=1;j<=n;j++)
                               
if(A[i][j]!=0) 

                                          TA[k++]=A[i][j];
                                printf("压缩后的三对角矩阵:\n");
                               
for(k=0;k<=n*n-1;k++)
                                          printf("%-4d",TA[k]);
}
 
void add()
{
  inti,j,k;
  printf("请输入要操作的三对角矩阵的阶数:");
  scanf("%d",&n);
 
  printf("输入三对角矩阵A:");
  for(i=1;i<=n;i++)
  {
             if(i==1)
             {
                       for(j=1;j<=2;j++)
                                  scanf("%d",&A[i][j]);
             }
             elseif(i>1&&i<n)
             {
                       for(j=i-1;j<=i+1;j++)
                                  scanf("%d",&A[i][j]);
             }
             elseif(i=n)
             {
                       for(j=i-1;j<=i;j++)
                                  scanf("%d",&A[i][j]);
             }
  }
  printf("输出三对角矩阵A:\n");
    for(i=1;i<=n;i++)
           {
        for(j=1;j<=n;j++)
                                printf("%-4d",A[i][j]);
                     printf("\n");
           }
          
           k=0;
           for(i=1;i<=n;i++)          
                     for(j=1;j<=n;j++)
                               
if(A[i][j]!=0) 

                                          TA[k++]=A[i][j];
                                printf("压缩后的三对角矩阵A:\n");
                               
for(k=0;k<=n*n-1;k++)
                                          printf("%-4d",TA[k]);
                                printf("\n");
  printf("输入三对角矩阵B:");
  for(i=1;i<=n;i++)
  {
             if(i==1)
             {
                       for(j=1;j<=2;j++)
                                  scanf("%d",&B[i][j]);
             }
             elseif(i>1&&i<n)
             {
                       for(j=i-1;j<=i+1;j++)
                                  scanf("%d",&B[i][j]);
             }
             elseif(i=n)
             {
                       for(j=i-1;j<=i;j++)
                                  scanf("%d",&B[i][j]);
             }
  }
  printf("输出三对角矩阵B:\n");
    for(i=1;i<=n;i++)
           {
        for(j=1;j<=n;j++)
                                printf("%-4d",B[i][j]);
                     printf("\n");
           }
 
  k=0;
  for(i=1;i<=n;i++)      

      for(j=1;j<=n;j++)
      if(B[i][j]!=0) 

     TC[k++]=B[i][j];
      printf("压缩后的三对角矩阵B:\n");
      for(k=0;k<=n*n-1;k++)
               printf("%-4d",TC[k]);
 
           intTB[MaxN];
           for(k=0;k<=n*n-1;k++)
                     TB[k]=TA[k]+TC[k];
           printf("相加后的压缩三对角矩阵:\n");
           for(k=0;k<=n*n-1;k++)
                     printf("%-4d",TB[k]);
           printf("\n");
}
 
//主菜单
int menu_list()
{
            int c;    

     printf("\n\n**************************特殊矩阵的压缩存储**************************\n\n");
            printf("               1.对称矩阵的压缩存储\n");
            printf("               2.上三角矩阵的压缩存储\n");
            printf("               3.下三角矩阵的压缩存储\n");
            printf("               4.三对角矩阵的压缩存储\n");
            printf("               5.三对角矩阵的加法运算\n");
            printf("               6.退出系统\n");
            printf("              
请输入(1-6)[ ]\b\b");
                      
            while(1)
            {
                      scanf("%d",&c);
                      if(c<1||c>6)
                          printf("输入错误,请重新输入:");
         else
                          break;
            }
            return c;
}
 
//主函数
void main()
{
           while(1)
           {        
               switch(menu_list())
                     {
                        case 1:                      

                            value();
                                  
break;
                        case 2:
                                sfdg();
                                  
break;
                        case 3:
                                   sfvd();
              break;
                        case 4:
                                   store();
                                  
break;
                        case 5:
                            add();
                                  
break;
                        case 6:
                                   printf("  
程序结束,谢谢您的使用!\n\n");
                                   exit(0);
                     }
           }
}
 

 

 

 

 

 

4.  稀疏矩阵压缩存储

 

4.1      定义

//定义结构体 

#defineMAXSIZE100 

typedefstruct 


    inti,j; 

    intdat; 

}Triple; 

//矩阵的顺序链表 

typedefstruct 


    Tripledata[MAXSIZE+1]; 
    intmu,nu,tu; 

}TSMatrix; 

 

 

 

4.2      FastConvert

输入两个参数M,和T的指针。

通过M.nu创建内存空间,分别给num和cpot。

将M的值复制给T矩阵。

Num是每列非零元素个数的数组。

Cpot是每列第一个非零元素位置 

 

//稀疏矩阵存储 

int FastConvert(TSMatrixM,TSMatrix
*T) 


    int*num,*cpot,i,p,col; 

    //分别为一维指针分配内存 
    num=(int*)malloc(sizeof(int)*M.nu); 

    cpot=(int*)malloc(sizeof(int)*M.nu); 

 
    T->mu=M.nu;T->nu=M.mu;T->tu=M.tu; 

 
    if(T->tu) 

    {  
        //初始化每一列非零元素个数为零 
         for(i=0;i<M.nu;i++)  

            num[i]=0; 
         //初始化数组将其置为每一列的非零元素个数 

         for(i=0;i<M.tu;i++) 

            ++num[M.data[i].j]; 

         //cpot数组表示每一列第一个非零元素位置 
        cpot[0]=0; 
         for(i=1;i<M.nu;i++) 

            cpot[i]=cpot[i-1]+num[i-1]; 

         //进行矩阵值的交换 
         for(i=0;i<M.tu;i++) 

        { 
             col=M.data[i].j;  p=cpot[col]; 
              T->data[p].i=M.data[i].j; 

              T->data[p].j=M.data[i].i; 

              T->data[p].dat=M.data[i].dat; 

             ++cpot[col]; 
        } 
    } 
    return1; 



 

4.3      Main

定义变量T,M。定义矩阵指针为NULL。输入行和列数量。

然后创建行数乘以列数的的整型指针数量。然后输入数据。

如果为0,则不增加变量tu和count的值。然后调用FastConvert函数。

运行如下图2 所示:

可以看到最后将一个稀疏矩阵成功的转化成为了一个数组。

不过需要注意的是:

稀疏矩阵压缩存储后,必会失去随机存取功能。

稀疏矩阵在采用压缩存储后将会失去随机存储的功能。因为在这种矩阵中,非零元素的分布是没有规律的,为了压缩存储,就将每一个非零元素的值和它所在的行、列号做为一个结点存放在一起,这样的结点组成的线性表中叫三元组表,它已不是简单的向量,所以无法用下标直接存取矩阵中的元素。

 

 

int main(intargc,char*
argv[]) 


    TSMatrixT,M; 

    intcol,row,i,j,count=0; 

    int**p=NULL; 
 
    printf("请输入矩阵的行列row
和 col\n"); 

    scanf("%d%d",&row,&col); 

    //为未知的二维指针分配内存 
    p=(int**)malloc(sizeof(int*)*row); 

    for(i=0;i<row;i++) 

        p[i]=(int*)malloc(sizeof(int)*col); 

   
 
    printf("请输入数据!\n"); 

 
   M.mu=row;  M.nu=col;  M.tu=0; 
    for(i=0;i<row;i++) 

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

        { 
           scanf("%d",&p[i][j]); 

            if(p[i][j]!=0) 

           { 
               M.data[count].dat=p[i][j]; 

               M.data[count].i=i; 

                M.data[count].j=j; 

               M.tu++; 
               count++; 
           } 
 
        } 
   count=0; 
   FastConvert(M,&T); 
    for(i=0;i<T.tu;i++) 

    { 
       printf("%d ",T.data[count].dat); 

       count++; 
    } 
   free(p); 
    return0; 



4.4      源码

#include<stdio.h> 

#include<stdlib.h> 

 
//定义结构体 

#defineMAXSIZE100 

typedefstruct 


    inti,j; 

    intdat; 

}Triple; 

//矩阵的顺序链表 

typedefstruct 


    Tripledata[MAXSIZE+1]; 
    intmu,nu,tu; 

}TSMatrix; 

 
int FastConvert(TSMatrixM,TSMatrix
*T); 
 
int main(intargc,char*
argv[]) 


    TSMatrixT,M; 

    intcol,row,i,j,count=0; 

    int**p=NULL; 
 
    printf("请输入矩阵的行列row
和 col\n"); 

    scanf("%d%d",&row,&col); 

    //为未知的二维指针分配内存 
    p=(int**)malloc(sizeof(int*)*row); 

    for(i=0;i<row;i++) 

        p[i]=(int*)malloc(sizeof(int)*col); 

   
 
    printf("请输入数据!\n"); 

 
   M.mu=row;  M.nu=col;  M.tu=0; 
    for(i=0;i<row;i++) 

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

        { 
           scanf("%d",&p[i][j]); 

            if(p[i][j]!=0) 

           { 
               M.data[count].dat=p[i][j]; 

               M.data[count].i=i; 

               M.data[count].j=j; 

               M.tu++; 
               count++; 
           } 
 
        } 
   count=0; 
   FastConvert(M,&T); 
    for(i=0;i<T.tu;i++) 

    { 
       printf("%d ",T.data[count].dat); 

       count++; 
    } 
   free(p); 
    return0; 


//稀疏矩阵存储 

int FastConvert(TSMatrixM,TSMatrix
*T) 


    int*num,*cpot,i,p,col; 

    //分别为一维指针分配内存 
    num=(int*)malloc(sizeof(int)*M.nu); 

    cpot=(int*)malloc(sizeof(int)*M.nu); 

 
    T->mu=M.nu;T->nu=M.mu;T->tu=M.tu; 

 
    if(T->tu) 

    {  
        //初始化每一列非零元素个数为零 
         for(i=0;i<M.nu;i++)  

            num[i]=0; 
         //初始化数组将其置为每一列的非零元素个数 

         for(i=0;i<M.tu;i++) 

            ++num[M.data[i].j]; 

         //cpot数组表示每一列第一个非零元素位置 
        cpot[0]=0; 
         for(i=1;i<M.nu;i++) 

             cpot[i]=cpot[i-1]+num[i-1]; 

         //进行矩阵值的交换 
         for(i=0;i<M.tu;i++) 

        { 
             col=M.data[i].j;  p=cpot[col]; 
              T->data[p].i=M.data[i].j; 

              T->data[p].j=M.data[i].i; 

              T->data[p].dat=M.data[i].dat; 

             ++cpot[col]; 
        } 
    } 
    return1; 



 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: