1. 程式人生 > >三元組表示的稀疏矩陣的加法和乘法

三元組表示的稀疏矩陣的加法和乘法

#include <stdio.h>
#include <stdlib.h>
//函式結果狀態碼
#define OK        1
#define ERROR     0
#define OVERFLOW -1 
//Status是函式的型別,其值是函式結果狀態程式碼
typedef int Status;
// ----- 稀疏矩陣的三元組順序表儲存表示 -----
#define MAXSIZE 100                      //假設非零元個數的最大值為100
#define MAXRC   100
typedef struct {
        int i,j;                           //非零元的行下標和列下標
        int e;                             //非零元的值
}Triple;
typedef struct {
        Triple data[MAXSIZE + 1];          //非零元三元組表,data[0]未用
        int    rpos[MAXRC + 1];            //各行的第一個非零元的位置表 
        int    mu, nu, tu;                 //矩陣的行數、列數和非零元個數 
}RLSMatrix;

Status CreateSMatrix(RLSMatrix *M);                            //建立稀疏矩陣M,採用三元組儲存
Status PrintSMatrix(RLSMatrix M);                              //輸出稀疏矩陣M
Status AddSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q);     //求稀疏矩陣的和Q = M + N
Status MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q);    //求稀疏矩陣乘積Q = M ×N 

main()
{
    RLSMatrix A, B, C;//稀疏矩陣A、B和C均以三元組表作為儲存結構,C存放A、B相加相乘的結果 
    //建立稀疏矩陣A、B
    printf("請輸入稀疏矩陣A\n"); 
    CreateSMatrix(&A);
    printf("稀疏矩陣A為:\n");
    PrintSMatrix(A);
    printf("\n\n");
    printf("請輸入稀疏矩陣B\n");
    CreateSMatrix(&B);
    printf("稀疏矩陣B為:\n");
    PrintSMatrix(B);
    printf("\n\n");
    //求稀疏矩陣的和C = A + B,並輸出相加結果矩陣C 
    if(AddSMatrix(A, B, &C))
    {
         printf("求疏矩陣的和C = A + B,並輸出相加結果矩陣C:\n");
         PrintSMatrix(C);
         printf("\n");
    }
    else printf("兩個矩陣行列數不完全相等,不是同類矩陣,不能相加。\n" );
    
    //求稀疏矩陣乘積C = A ×B,並輸出相乘結果矩陣C
    if(MultSMatrix(A, B, &C))
    {
         printf("稀疏矩陣乘積C = A ×B,並輸出相乘結果矩陣C:\n");
         PrintSMatrix(C);
         printf("\n");
    }
    else printf("稀疏矩陣A的列數和B的行數不相等,不能相乘。\n");
    printf("\n");
    //程式結束
    system("pause");
    return 0; 
}
//建立稀疏矩陣M,採用三元組表儲存表示
Status CreateSMatrix(RLSMatrix *M)
{
       int m, n, t, e;                //行數m,列數n,非零元個數t和非零元值e 
       int i, j, k, a, b;                   //中間變數
       int num[MAXSIZE];              //每行非零元素個數
       int flag [MAXSIZE][MAXSIZE];   //標記陣列:此位置是否已經有非零元素 
       
       for(i = 0; i < MAXSIZE; i++)   //標記陣列的初始化 
            for(j = 0; j < MAXSIZE; j++)
                 flag [i][j] = 0;
                  
       //輸入M的行數、列數和非零元個數
       do {
          printf("請分別輸入矩陣的行數、列數和非零元個數:\n"); 
          printf("行數:");
          scanf("%d", &m);
          printf("列數:");
          scanf("%d", &n);
          printf("非零元的個數:");
          scanf("%d", &t);
          if(m < 0 || n < 0 || t < 0 || t > m * n) printf("輸入的資料不符合要求!!!");
       } while(m < 0 || n < 0 || t < 0 || t > m * n);
       M->mu = m, M->nu = n, M->tu = t;//儲存 
       //按行序輸入非零元
       if(t == 0) return OK;
       for(k = 1; k <= t; k++)
       {
            do {
               printf("請輸入第%d個非零元(總共%d個)的行和列:\n", k, t);
               printf("對應行:");
               scanf("%d", &i);
               printf("對應列:");
               scanf("%d", &j);              
               if(i <= 0 || i > m || j <= 0 || j > n) 
                    printf("輸入行或列不符合要求!!!\n");
               if(flag [i][j] != 0) {
                    printf("此處已存在非零元素!!!\n");
                    flag [i][j] = 2;
               }
               else
                    flag [i][j] = 1;      
            } while(i <= 0 || i > m || j <= 0 || j > n || flag [i][j] == 2);//檢測輸入是否合法 
 
            do {
               printf("非零元:");
               scanf("%d", &e);
               if(e == 0) printf("輸入為0,請重新輸入!!!\n");
            } while(e == 0); //檢測輸入是否合法 
            //按行序儲存資料 
            for(a = 1; a <= k-1 && (i > M->data[a].i || (i == M->data[a].i && j > M->data[a].j)); a++);//找到此三元組插入的位置 
            for(b = k-1; b >= a; b--)
                 M->data[b+1] = M->data[b];//行序比它大的三元組依次向後移動 
            M->data[a].i = i, M->data[a].j = j, M->data[a].e = e;//儲存資料
       }
       //求rpos
       if(M->tu)
       {
            for(i = 1; i <= M->mu; i++) num[i] = 0;//初始化 
            for(t = 1; t <= M->tu; t++) ++num[M->data[t].i];//求M中每一行含非零元素個數
            //求rpos
            M->rpos[1] = 1;
            for(i = 2; i <= M->mu; i++) M->rpos[i] = M->rpos[i-1] + num[i-1]; 
       }  
       return OK;          
}
//輸出稀疏矩陣M
Status PrintSMatrix(RLSMatrix M)
{
       int i, j, k;//中間變數
       //輸出
       for(i = 1, k = 0; i <= M.mu; i++)
       {
            for(j = 1; j <= M.nu; j++)
            {
                 if(M.data[k+1].i == i && M.data[k+1].j == j) 
                 {
                      printf("%d\t", M.data[k+1].e);
                      k++;
                 }
                 else printf("0\t");
            }
            printf("\n");
       }
       printf("矩陣共有%d行%d列共%d個非零元素", M.mu, M.nu, M.tu);
       return OK;
}
//求稀疏矩陣的和Q = M + N
Status AddSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q)
{
       int i = 1, j = 1, k = 1;              //中間變數   
       //檢查稀疏矩陣M和N的行數和列數是否對應相等 
       if(M.mu != N.mu || M.nu != N.nu) 
       {//不完全相等,退出 
            return ERROR;   
       }
       if(M.tu * N.tu == 0) return OK;//Q為零矩陣,直接返回 
       //初始化矩陣Q
       Q->mu = M.mu, Q->nu = M.nu, Q->tu = 0;
       //執行矩陣相加,按行的順序相加,分為四種情況 
       while(i <= M.tu && j <= N.tu)//M和N均不為空 
       {
            if((M.data[i].i == N.data[j].i && M.data[i].j < N.data[j].j) || (M.data[i].i < N.data[j].i))//矩陣M當前元素在矩陣N當前元素的前面 
            {
                 Q->tu++;//非零元素增加
                 Q->data[k].i = M.data[i].i, Q->data[k].j = M.data[i].j, Q->data[k].e = M.data[i].e;//賦值
                 i++, k++;//移動指標 
            }
            else if((M.data[i].i == N.data[j].i && M.data[i].j > N.data[j].j) || (M.data[i].i > N.data[j].i))//矩陣M當前元素的在矩陣N當前元素的後面 
            {
                 Q->tu++;//非零元素增加
                 Q->data[k].i = N.data[j].i, Q->data[k].j = N.data[j].j, Q->data[k].e = N.data[j].e;//賦值
                 j++, k++;//移動指標 
            }
            else if(M.data[i].e + N.data[j].e)//M和N當前結點對應且兩元素之和不為零
            {
                 Q->tu++;//非零元素增加
                 Q->data[k].i = N.data[j].i, Q->data[k].j = N.data[j].j, Q->data[k].e = M.data[i].e + N.data[j].e;//賦值
                 i++, j++, k++;//移動指標 
            } 
            else //M和N當前結點對應且兩元素之和為零
            {
                 i++, j++;//指標向右移
            }
       }
       //將矩陣M的剩餘元素插入矩陣Q    
       while(i <= M.tu)
       {
            Q->tu++;//非零元素增加
            Q->data[k].i = M.data[i].i, Q->data[k].j = M.data[i].j, Q->data[k].e = M.data[i].e;//賦值
            i++, k++;//移動指標 
       } 
       //將矩陣N的剩餘元素插入矩陣Q 
       while(j <= N.tu)
       {
            Q->tu++;//非零元素增加
            Q->data[k].i = N.data[j].i, Q->data[k].j = N.data[j].j, Q->data[k].e = N.data[j].e;//賦值
            j++, k++;//移動指標 
       } 
       return OK;
}
//求稀疏矩陣乘積Q = M ×N 
Status MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q)
{
       int arow, brow, ccol, i, t, ctemp[N.nu+1], p, q, tp;//中間變數 
       //檢查稀疏矩陣M的列數和N的行數是否對應相等 
       if(M.nu != N.mu) return ERROR;//稀疏矩陣M的列數和N的行數不相等,不能相乘,退出 
       //初始化矩陣Q
       Q->mu = M.mu, Q->nu = N.nu, Q->tu = 0;
       //相乘
       if(M.tu * N.tu != 0)//Q是非零矩陣
       {
            for(arow = 1; arow <= M.mu; ++arow)//處理M的每一行 
            {
                 for(i = 0; i <= N.nu; ++i) ctemp[i] = 0;//當前行各元素累加器清零
                 Q->rpos[arow] = Q->tu + 1;
                 if(arow < M.mu) tp = M.rpos[arow + 1];
                 else tp = M.tu +1;
                 for(p = M.rpos[arow]; p < tp; ++p)//對當前行中的每一個非零元 
                 {
                      brow = M.data[p].j;          //找到對應元在N中的行號
                      if(brow < N.mu) t = N.rpos[brow+1];
                      else t = N.tu + 1;
                      for(q = N.rpos[brow]; q < t; ++q)
                      {
                           ccol = N.data[q].j;      //乘積元素在Q中列號
                           ctemp[ccol] += M.data[p].e * N.data[q].e; 
                      } 
                 }//求得Q中第crow( = arow)行的非零元
                 for(ccol = 1; ccol <= Q->nu; ++ccol)  //壓縮儲存該行非零元
                 {
                      if(ctemp[ccol])//非零元 
                      {
                           if(++(Q->tu) > MAXSIZE) return ERROR;
                           Q->data[Q->tu].i = arow, Q->data[Q->tu].j = ccol, Q->data[Q->tu].e = ctemp[ccol];          
                      }    
                 } 
            }   
       } 
       return OK;
}