首页 > 其他分享 >稀疏矩阵转置

稀疏矩阵转置

时间:2022-10-02 07:55:32浏览次数:78  
标签:转置 矩阵 稀疏 三元组 int data col

稀疏矩阵转置

前置知识:稀疏矩阵用三元组的保存

一般来说,对于系数矩阵,我们使用三元组来存储。即就是将矩阵的所有非零元素的三元组存放在一个顺序表中,如图所示:

image-20221001154338923

注意一个转置的前提:该顺序表是排好序的,即行优先,列其次。

这里的稀疏矩阵为静态分配空间,所以会有MAXSIZE+1个三元组,但实际上转置时遍历是按照len长度来遍历的

img

图 2a) 表示的是图 1 中转置之前矩阵的三元组表,2b) 表示的是图 1 中矩阵转置后对应的三元组表。

矩阵转置的实现过程需完成以下 3 步:

  1. 将矩阵的行数和列数互换;
  2. 将三元组表(存储矩阵)中的 i 列和 j 列互换,实现矩阵的转置;
  3. 以 j 列为序,重新排列三元组表中存储各三元组的先后顺序;

一、普通转置

实现思路是:

不断遍历存储矩阵的三元组表,每次都取出表中 j 列最小的那一个三元组,互换行标和列标的值,并按次序存储到一个新三元组表中,。

例如,将图 2a) 三元组表存储的矩阵进行转置的过程为:

  1. 新建一个三元组表(用于存储转置矩阵),并将原矩阵的行数和列数互换赋值给新三元组;
  2. 遍历三元组表,找到表中 j 列最小值 1 所在的三元组 (3,1,6),然后将其行标和列标互换后添加到一个新的三元组表中,如图 3 所示:

在这里插入图片描述

  1. 继续遍历三元组表,找到表中 j 列次小值为 2 的三元组,分别为 (1,2,1)、(2,2,3) 和 (3,2,5),根据找到它们的先后次序将各自的行标和列标互换后添加到新三元组表中,如图 4 所示:

    注:因为文章要求开头提到了,转置的前提是"该顺序表是排好序的,即行优先,列其次。",所以按照遍历到他们的先后顺序(在原矩阵中data下标按行递增查找)放入新矩阵后,他们按照j也是有序的(此时i相同)。

    img

对比图 4 和图 2b) 可以看到,矩阵被成功地转置。

基于上面描述的代码有:

代码

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

#define MAXSIZE 1000
#define number 10

//定义三元组
typedef struct{
    int row;//第几行
    int col;//第几列
    int val;//存储的数值
} Triple;

//定义稀疏矩阵
typedef struct{
    Triple data[MAXSIZE];
    int m, n, len; //稀疏矩阵的行、列、非零元素的个数
} TSMatrix;

void TransMatrix(TSMatrix *, TSMatrix *);

int main(void){
    TSMatrix M;
    M.m = 4;
    M.n = 3;
    M.len = 4;
    M.data[1].row = 1;
    M.data[1].col = 2;
    M.data[1].val = 1;

    M.data[2].row = 2;
    M.data[2].col = 2;
    M.data[2].val = 3;

    M.data[3].row = 3;
    M.data[3].col = 1;
    M.data[3].val = 6;

    M.data[4].row = 3;
    M.data[4].col = 2;
    M.data[4].val = 5;

    TSMatrix T;
    for (int k = 0; k < number; k++) {
        T.data[k].row = 0;
        T.data[k].col = 0;
        T.data[k].val = 0;
    }
    TransMatrix(&M, &T);
    for (int i = 1; i <= T.len; i++) {
        printf("(%d,%d,%d)\n", T.data[i].row, T.data[i].col, T.data[i].val);
    }
    return 0;
}

//稀疏矩阵的转置,A为装置前矩阵,B为转置后矩阵
void TransMatrix(TSMatrix *A, TSMatrix *B){
    B->len = A->len;                 //复制A中非零元素个数至B
    B->m = A->n;                    //将A的行数与列数与B的交换
    B->n = A->m;
    int q = 1;                      //辅助计数器,记录转置后的三元组(下一个插入)元素下标值,
                                    //注意:这里A.data[]数组下标从1开始,三元组下标从0开始
    if(A){
        for (int col = 0; col < A->n; col++){      //按照列优先来遍历矩阵A(因为要先从列最小开始存放至新矩阵中)
            for (int p = 1; p <= A->len; p++){      //按照下标递增次序遍历三元组,寻找列下标一致的
                if(col==(A->data[p].col)){          //找到,则交换该三元组的行列下标放至新矩阵中
                    B->data[q].col = A->data[p].row;
                    B->data[q].row = A->data[p].col;
                    B->data[q].val = A->data[p].val;
                    q++;
                }
            }
        }
    }
}

运行结果见 图2a) 2b)

二、快速转置

思想:按稀疏矩阵的三元组(source)次序转置,转置结果放入新稀疏矩阵的三元组(dest)中的恰当位置。

  • 关键:
  1. 预先确定source中每一列第一个非零元在dest中位置。
  2. 为确定这些位置,转置前应先求得source的每一列中非零元个数

在这里插入图片描述

  • cpos[col] 的计算方法:

​ 初始:cpos[1]=1

​ 其他:cpos[col]=cpos[col-1]+num[col-1] (2<=col<=M.nu)

image-20221001171744257

代码

//用三元组表示(顺序存储)的稀疏矩阵的两种转置方法转置

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

#define MAXSIZE 1000
#define number 10

//定义三元组
typedef struct{
    int row;//第几行
    int col;//第几列
    int val;//存储的数值
} Triple;

//定义稀疏矩阵
typedef struct{
    Triple data[MAXSIZE];
    int m, n, len; //稀疏矩阵的行、列、非零元素的个数
} TSMatrix;

void Transpose(TSMatrix *, TSMatrix *);

int main(void){
    TSMatrix M;
    M.m = 4;
    M.n = 3;
    M.len = 4;
    M.data[1].row = 1;
    M.data[1].col = 2;
    M.data[1].val = 1;

    M.data[2].row = 2;
    M.data[2].col = 2;
    M.data[2].val = 3;

    M.data[3].row = 3;
    M.data[3].col = 1;
    M.data[3].val = 6;

    M.data[4].row = 3;
    M.data[4].col = 2;
    M.data[4].val = 5;

    TSMatrix T;
    for (int k = 0; k < number; k++) {
        T.data[k].row = 0;
        T.data[k].col = 0;
        T.data[k].val = 0;
    }
    // TransMatrix(&M, &T);
    Transpose(&M, &T);
    for (int i = 1; i <= T.len; i++) {
        printf("(%d,%d,%d)\n", T.data[i].row, T.data[i].col, T.data[i].val);
    }
    return 0;
}

void Transpose(TSMatrix *source, TSMatrix *dest){
    //采用三元组顺序表存储表示,求稀疏矩阵M的转置矩阵T
    int cNum[MAXSIZE] = {0};
    int sPos[MAXSIZE] = {0};
    dest->m = source->n;
    dest->n = source->m;
    dest->len = source->len; //将M的行数赋值给T的列数,将M的列数赋值给T的行数,非零元素总数也赋值过去
    for (int i=0; i<source->n; i++)
        cNum[i] = 0;                                  //初始化假设原三元组每一列元素出现次数都为0
    for (int i = 1; i <= source->len;i++)
        ++cNum[source->data[i].col];                 //枚举每一个非0元素, M.data[t].j 为其相应的列
    sPos[1]=1;                                       //求第 col列中第一个非零元在T.data中的序号
    for (int i=2; i<source->n; i++)                  //存储source第col列中第一个非零元素在dest的位置
        sPos[i] = sPos[i - 1] + cNum[i - 1];
    for (int p = 1; p <= source->len; ++p)
    {                                                  //枚举所有的三元组
        int col = source->data[p].col;                 //将第i个三元组的列数赋值给col
        int q=sPos[col];
        /*取出spot数组中spot[col]的值,注意,这里很重要:因为在顺序表中,所有的行元素的大小已经是依次排好的,
        所以我们遍历到的这个三元组时,当其与其后面的拥有相同列元素的三元组进行比较的时候,它一定是最小的,
        所以应该放在前面时,所以我们取完这个值之后,将spot[col]的值+1,即可在下面的遍历中搜索到与之邻近的
        值,正好下标已经+1,直接添加上去即可*/
        dest->data[q].row=source->data[p].col;
        dest->data[q].col=source->data[p].row;
        dest->data[q].val = source->data[p].val;         //赋值操作
        ++sPos[col];                                   //下标记录+1
    }
}

参考

稀疏矩阵的普通转置与快速转置算法

矩阵(稀疏矩阵)的转置算法(C语言)详解

稀疏矩阵简单转置方法

稀疏矩阵快速转置方法

标签:转置,矩阵,稀疏,三元组,int,data,col
From: https://www.cnblogs.com/komorebi-514/p/16748211.html

相关文章

  • 矩阵变量
    矩阵变量的语法:映射+路径+矩阵变量,多个变量用分号隔开开启矩阵变量方式1@Configuration(proxyBeanMethods=false)publicclassWebConfigimplementsWebMvcConfigurer{......
  • 稀疏数组
    稀疏数组packagearray;importjava.util.Arrays;publicclassSparse{publicstaticvoidmain(String[]args){//创建二维数组System.out.p......
  • 稀疏数组
    稀疏数组当一个数组中大部分元素为0,或者为同一值的数组时,可以使用稀疏数组来保存该数组。稀疏数组的处理方式是:记录数组-共有几行几列,有多少个不同值把具有不同值......
  • AM5728 Opencl 案例汇总:实现sobel算法,计算向量和,矩阵转置
    案例一:实现sobel算法OpenCV(Open Source Computer Vision Library)是一个基于BSD许可开源发行的跨平台计算机视觉库。实现图像处理和计算机视觉方面的很多通用计算。......
  • Arrays类、冒泡排序、稀疏数组
    Arrays类数组的工具类java.util.Arrays由于数组对象本身并没有什么方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作......
  • 【luogu CF618G】Combining Slimes(矩阵乘法)(DP)
    CombiningSlimes题目链接:luoguCF618G题目大意有一个长度为n的栈,如果栈顶两个值都是x就会合并成x+1,一开始没有东西。你有p的概率放进去一个1,1-p的概率放入2......
  • #yyds干货盘点# 面试必刷TOP101:矩阵的最小路径和
    1.简述:描述给定一个 n*m 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。数据范......
  • 24. NumPy矩阵乘法
    1.前言矩阵乘法是将两个矩阵作为输入值,并将A矩阵的行与B矩阵的列对应位置相乘再相加,从而生成一个新矩阵,如下图所示:注意:必须确保第一个矩阵中的行数等于第二个矩阵中......
  • 19、Opencv4.4的仿射矩阵处理
    基本思想:深入学习一下仿射矩阵的使用和分解环境window10+Mingw32+Opencv4.4.0+Eigen这里仅说明一下Eigen库的导入方法,首先去Eigen官网下载Eigen源码,解压导入Clion工程中,修......
  • 矩阵相关
    \[\begin{bmatrix}a&b\\c&d\end{bmatrix}\]矩阵乘法基础部分e.g.\[\begin{bmatrix}a_{1,1}&a_{1,2}\\a_{2,1}&a_{2,2}\end{bmatrix}\begin{b......