数据结构_稀疏矩阵的相关操作函数:(转置,相加,相乘) 运行实例:(C实现)

文章目录

  • 宏定义/包含
  • 初始化稀疏矩阵
  • 定义数据结构
  • 输出稀疏矩阵
  • 主要操作:
    • 稀疏矩阵转置
    • 稀疏矩阵相加
    • 稀疏矩阵相乘
  • 通用主函数(测试)
  • 测试数据
  • 效果截图

稀疏矩阵的相关操作函数:(转置,相加,相乘)
运行实例:

宏定义/包含

#define _CRT_SECURE_NO_WARNINGS
#define   EMPTY_QUEUE_ERROR   -999999
#include 
#include 
#include 
#include 
#include 
#define MAXLEN 100
typedef int ElemType;

#define MAXNUM 40   // 假定非零元素个数不超过20个

初始化稀疏矩阵

/*
矩阵素材:

mat1:

0 0 0 0 0 1 0
0 0 0 2 0 0 0
0 3 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 2 0 0 0

mat2:

0 0 0 0 0 1 0
0 0 0 2 0 1 0
0 3 0 6 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
*/


/*(25)根据 二维数组   初始化一个稀疏矩阵结构体
二维数组中包含  少量非零元素,通过  遍历该二维数组,
将非零元素信息填入稀疏矩阵 结构体中。为简化起见,假定二维数组为 六行七列。
*/
#define ROWS 6
#define COLS 7
/*输入二维矩阵(含有一些非零元素*/
void BuildSparseMatrix(int m[ROWS][COLS], SparseMatrix* pSM)
{
    int i, j, n = 0;  // 用于统计非零元素个数

    // 遍历该二维数组
    for (i = 0;i<ROWS;i++)
        for (j = 0;j<COLS;j++)
        {
            // 如果找到非零元素
            if (m[i][j])
            {
                // 保存非零元素信息到(添加该元素到)三元组数组中相应的那个三元组中(三元组的三个分量(行,列,值)
                pSM->elem[n].r = i+1;
                pSM->elem[n].c = j+1;
                pSM->elem[n].e = m[i][j];
                ++n;
            }
        }

    // 分别保存稀疏矩阵的总行数、总列数和非零元素个数	  
    pSM->nrow = ROWS;
    pSM->ncol = COLS;
    pSM->num = n;
}


定义数据结构

/*矩阵中的单个元素(非零元素)的数据结构*/
typedef struct {
    int r, c, e;   // 非零元素的行、列和数据值/*从行和列1开始计数*/
}Triple;
/*稀疏矩阵整体(zheng'ti)的数据结构(已压缩)*/
typedef struct {
    //非零元素信息数组
   Triple elem[MAXNUM];/*elem[0]三元组保存的事整个矩阵的行数,列数,非零元素个数*/
    //分别保存稀疏矩阵的总行数、总列数和非零元素个数
    int nrow, ncol, num;
}SparseMatrix;/*sparse /spɑːrs/ adj.稀少的, 稀疏的*/

输出稀疏矩阵

/*(26)输出稀疏矩阵(
(根据(gen'ju)稀疏矩阵压缩结构体,解压出原矩阵中(r,c)位置的元素) 该函数还可以配合循环,将三元组形式的稀疏矩阵按照二维数组的形式输出。稀疏矩阵的解压较为简单*/
int Get(SparseMatrix* pSM, int r, int c)
{
    /**********************************************************
     从稀疏矩阵中得到第r行c列元素的值
 *********************************************************/
    int i = 0;
    /*遍历查找的过程:*/
    // 遍历该稀疏矩阵的三元组数组
    for (; i < pSM->num; i++)
    {
        // 若找到第r行第c列的非零值,则返回该值
        if (pSM->elem[i].r == r && pSM->elem[i].c == c)
            return pSM->elem[i].e;
    }

    // 若没有找到第r行第c列的数据,则必然是0
    return 0;
}

void PrintSMatrix(SparseMatrix* pSM)
{
    int  i, j;
    /*全遍历*/
    for (i = 1; i <= pSM->nrow; i++)/*注意从1开始*/
    {
        for (j = 1; j <= pSM->ncol; j++)
            printf("%d\t",Get(pSM,i,j)); // 输出第i行第j列元素的值(在主函数之外调用 &参数是愚蠢的.(定以复合函数时,内部函数的指针参数不要&比如:错误的Get(&pSM,i,j))
        printf("\n");
    }
}

主要操作:

稀疏矩阵转置

/*(27)稀疏矩阵的转置
(快速转置):
引入了两个辅助的存储空间starting_pos和row_terms将A转置为B。

其中 数组row_terms中存放的是  各行 非零元素的 个数,
数组starting_pos用来存储  转置后的矩阵 每行非零元素的 起始地址。*/
void Translate3(SparseMatrix* pMatA, SparseMatrix* pMatB)
{
    int i;
    // 定义两个辅助数组;从0开始计数.
    int row_terms[COLS], /*数组row_terms中存放的是  各行 非零元素的 个数*/
        starting_pos[COLS];/*用来存储  转置后的矩阵 每行非零元素的 起始地址(在三元组数组中)*/

    // 转置后,行列值交换,但非零元素个数不变
    pMatB->ncol = pMatA->nrow;
    pMatB->nrow = pMatA->ncol;
    pMatB->num = pMatA->num;

    // 统计转置后每行元素个数

    // 首先将每行元素  个数置零
    for (i = 0; i < pMatB->nrow; i++)
        row_terms[i] = 0;

    //遍历 一遍矩阵A中的 非零值信息,计算转置之后每行非零元素个数
    /*核心步骤1(用数组row_terms[]巧妙地统计矩阵A中各列非零元素的个数(同时也是矩阵B各行的非0元素的个数.)
    这种根据元素的信息填充/增加计数到对应列(对矩阵B来说是行)的方式比根据位置判断其上的元素(是否为0)一般都要要来的高效.*/
    for (i = 0; i < pMatA->num; i++)/*从三元组列表中无空洞查找*/
        row_terms[pMatA->elem[i].c - 1]++;
    /*其中:  pMatA->elem[i].c (是矩阵A的非零元素信息数组中第i个元素的所在列号,随着i的增长,这个表达式(记为k)的值的取值将落在 1,2,...pMatA->ncol 以内(且可以重复);注意在数组下标就要从0计数 (用户计数-1)*/
  
     /*核心步骤2*/
    /* 计算在转置之后 每一行(各行在非零元素(三元组)数组中)起始写入位置
    显然, 第1行的写入位置也在三元组数组的0号位置  */
    starting_pos[0] = 0;
    /* 从第2行开始(下标i= 1), 递推公式:第i行的起始写入位置是其前一行 (第i-1行的起始写入位置+第i-1 行的非零元素个数)
    迭代过程:(初始化/准备起点+迭代公式)*/
    for (i = 1; i < pMatA->ncol; i++)
        starting_pos[i] = starting_pos[i - 1] + row_terms[i - 1];

    
    /*核心步骤3*/
   // 有了两个辅助数组,再次扫描A矩阵(中的三元组数组表)
    for (i = 0; i < pMatA->num; i++)
    {
        // A中的第i个非零值转置之后为B的第几行?pMatA->elem[i].c; 从starting_pos[]数组 中查找到第k行的在三元组数组中的起始写入位置:starting_pos[k](在三元组数组中的该位置处写入矩阵中的k行的下一个非0元素.
        pMatB->elem[starting_pos[pMatA->elem[i].c - 1]].r = pMatA->elem[i].c;/*pMatA->elem[i].c,(不妨将该表达式记为k)即A中的第i个非零元素的所在列号,也是该元素(pMatA->elem[i])要填充在矩阵B的所在行的行号;再找到矩阵B中第k行的 起始位置:starting_pos[k],每填充一个,位置后移一,也就是说,起始位置starting_pos[k]是要不断迭代的;注意k没有变,变的是整体(starting_pos[k])这一变量:
该语句的化简写法:pMatB->elem[ starting_pos[k] - 1].r = k;
*/
        pMatB->elem[starting_pos[pMatA->elem[i].c - 1]].c = pMatA->elem[i].r;
         
        pMatB->elem[starting_pos[pMatA->elem[i].c - 1]].e = pMatA->elem[i].e;

        // B中的第几行写入数据后, starting_pos中相应行的写入位置 后移一位
        starting_pos[pMatA->elem[i].c - 1]  ++;/*rting_pos[pMatA->elem[i].c - 1] 是一个整数,用以指示数组下标(引导填充位置)*/
    }
}

稀疏矩阵相加

/*(28)稀疏矩阵相加
试根据函数原型,写出稀疏矩阵C = A + B的函数。参数要求:两个参数矩阵的规格一摸一样,结果矩阵也是该规格:*/
void Add(SparseMatrix* pMatA, SparseMatrix* pMatB, SparseMatrix* pMatC)/*解压矩阵后再相加*/
{
    int index = 0;
    int x1 = 0,
        x2 = 0;
    for (int i = 1; i <= pMatA->nrow; i++)
    {
        for (int j = 1; j <= pMatB->ncol; j++)/*pMatA也行,任意,因为规格一样*/
        {
            x1 = Get(pMatA, i, j);
            x2 = Get(pMatB, i, j);
            if (x1 || x2)//这里的Get(又多写了&);注意短路问题呀:(x1 = Get(pMatA, i, j)) || (x2 = Get(pMatB, i, j))一旦前部非0,后部x2就无法获得更新/计算
            {
                /*三元组必须同时更改*/
                pMatC->elem[index].e = x1 + x2;/*重新压缩的策略*/
                pMatC->elem[index].r = i;/*i,j,r,c,均是从1开始计数*/
                pMatC->elem[index].c = j;
                index++;/*计数器,写入一个自增1*/
            }
           /* if(pMatA->)
            pMatC->elem[index++] += pMatB->elem[j];*/
        }//for
           
    }//for
    /*勿忘修改矩阵总体信息(规格,方便打印)建议放在函数头部:*/
    pMatC->ncol = pMatA->ncol;
    pMatC->nrow = pMatA->nrow;
    pMatC->num = index ;
    //index = 0;
    
}

稀疏矩阵相乘

/*(29)稀疏矩阵相乘
注意先明确操作函数的参数对象要求:矩阵规格必须分别是:a*k以及k*b,结果矩阵规格为a*b(计算每个C中的元素,都是一个k项式之和)
    矩阵先后顺序不可掉换.
试根据函数原型,写出稀疏矩阵C = A * B的函数。*/
void Mul(SparseMatrix* pMatA, SparseMatrix* pMatB, SparseMatrix* pMatC)
{
    /*处理矩阵C的统计信息*/
    pMatC->nrow = pMatA->nrow;
    pMatC->ncol = pMatB->ncol;
    int x1,
        x2;
    int index = 0;
    int temp_s = 0;
    /*根据位置填值*/
    for (int i = 0; i < pMatA->nrow; i++)/*矩阵A,B规格不相同了*/
    {
        for (int j = 0; j < pMatB->ncol; j++)
		{
            /*填充单个元素(求矩阵C的(i,j)位置上的元素值,并将非零元素的行列信息一并保存到三元组表中*/
            temp_s = 0;
        /*计算k项式的值(求和);同时也是结果矩阵的(i,j)位置上的元素.*/
			for (int k = 1; k <= pMatA->ncol; k++)
			{
                temp_s += (Get(pMatA, i, k) * Get(pMatB, k, j));
                if (temp_s)/*将其中的非0元素压到三元组数组中去*/
                {
                    pMatC->elem[index].e = temp_s;
                    pMatC->elem[index].r = i;
                    pMatC->elem[index].c = j;
                    index++;

                }
				

			}
			
		}
    }

    pMatC->num = index ;

}

通用主函数(测试)

/*(30)调试
根据上述稀疏矩阵定义,,完成下面代码,运行并调试程序。*/
void fill_two_dimenssion_array_2(int(*arr_2)[COLS])
{
    printf("创建并填充二维数组:\n");
    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; j < COLS; j++)
        {
            scanf("%d", &arr_2[i][j]);
        }
    }
}
int main()
{
    // 定义两个二维数组a和b,用少量 非零值 初始化a和b
    int a[ROWS][COLS],
        b[ROWS][COLS];
    fill_two_dimenssion_array_2(a);
    fill_two_dimenssion_array_2(b);
    //定义两个三元组形式稀疏矩阵mat1和mat2,分别用a和b初始化
    SparseMatrix
        mat1,
        mat2,
        mat3,
        mat4;
    /*一般的,矩阵mat1,mat2本身不受二维数组a,b规格的影响
    但矩阵mat_i中元素对以矩阵mat_i为参数的函数来说有影响*/
    BuildSparseMatrix(a, &mat1);
    BuildSparseMatrix(b, &mat2);
    //输出mat1和mat2
    /**/
    printf("输出mat1:\n");
    PrintSMatrix(&mat1);
    printf("输出mat2:\n");
    PrintSMatrix(&mat2);


    /**/
    // 定义三元组形式稀疏矩阵mat3, 计算mat3=mat1+mat2
       //输出mat3
    printf("测试Add(&mat1, &mat2, &mat3),并输出mat3:\n");
    Add(&mat1, &mat2, &mat3);
   /* */
    PrintSMatrix(&mat3);
    // 将mat3转置到mat2
    printf("测试Translate3(&mat3, &mat2):将mat3转置到mat2:\n");
    Translate3(&mat3, &mat2);
    //输出mat2
   /* */printf("输出矩阵转置结果(新)mat2:\n");
    PrintSMatrix(&mat2);
    
   // 定义三元组形式稀疏矩阵mat4, 计算mat4=mat1 * mat2
    printf("测试Mul(&mat1, &mat2, &mat4);并输出矩阵mat4:\n");
    Mul(&mat1, &mat2, &mat4);
       //输出mat4
   
    PrintSMatrix(&mat4);

}

测试数据


/*mat1:

0 0 0 0 0 1 0
0 0 0 2 0 0 0
0 3 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 2 0 0 0

mat2:

0 0 0 0 0 1 0
0 0 0 2 0 1 0
0 3 0 6 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
*/

效果截图

数据结构_稀疏矩阵的相关操作函数:(转置,相加,相乘) 运行实例:(C实现)_第1张图片

你可能感兴趣的:(数据结构_稀疏矩阵的相关操作函数:(转置,相加,相乘) 运行实例:(C实现))