经典算法题15-稀疏矩阵及三元组

一. 引入

我们知道矩阵是一个非常强大的数据结构,在动态规划以及各种图论算法上都有广泛的应用。

当然矩阵有着不足的地方就是空间和时间复杂度都维持在N²上,比如1w个数字建立一个矩阵,在内存中会占用1w*1w=1亿的类型空间,这时就会遇到outofmemory。。。

那么面临的一个问题就是如何来压缩矩阵,当然压缩的方式有很多种,这里就介绍一个顺序表的压缩方式:三元组

二. 介绍三元组

有时候我们的矩阵中只有零星的一些非零元素,其余的都是零元素,那么我们称之为稀疏矩阵,当然没有绝对的说有多少个零元素才算稀疏。简单说,稀疏矩阵就是非零元素个数远远小于元素个数的矩阵。相对于稀疏矩阵来说,一个不稀疏的矩阵也称作稠密矩阵。

针对上面的这个无规律的存放非零元素,三元组提出了一种方法,就是仅仅记录矩阵中的非零元素以及**它的行,列以及值**N(x,y,v)构成的一个三元组,标识一个稀疏矩阵的话,还要记录该矩阵的阶数,这样我们就将一个二维的变成了一个一维,极大的压缩的存储空间。
这里要注意的就是,三元组的构建采用“行”是从上到下,“列”也是从左到右的方式构建的顺序表。
这里写图片描述

package xm.math.matrix;

/**
 * 三元组处理稀疏矩阵
 *
 * @author xuming
 */
public class Node {

    public int x;
    public int y;
    public double value;

    public Node(int r, int c, double v) {
        this.x = r;
        this.y = c;
        this.value = v;
    }

    public Node() {
        this(0, 0, 0.0);
    }
}

其实说到这里也就差不多了,我们只要知道三元组是用来做矩阵压缩的一个顺序存储方式即可,然后知道怎么用三元组表来做一些常规的矩阵运算,好了,既然说已经做成线性存储了,那就做个转置(“行列置换”)试试。

三. 矩阵转置

做行列置换很容易,也就是交换”非零元素”的(x,y)坐标,要注意的就是,原先我们的三元组采用的是”行优先“,所以在做转置的时候需要遵循”列优先“。
这里写图片描述

 public Matrix convertMatrix(Matrix node) {
        Matrix matrix = new Matrix();
        matrix.rows = node.rows;
        matrix.cols = node.cols;
        matrix.count = node.count;
        for (int col = 0; col < node.cols; col++) {
            for (int triple = 0; triple < node.count; triple++) {
                Node t = node.nodes.get(triple);
                if (col == t.y) {
                    matrix.nodes.add(new Node(t.y, t.x, t.value));
                }
            }
        }
        return matrix;
    }

具体完整代码见我的githubhttps://github.com/shibing624/BlogCode/blob/master/src/main/java/xm/math/matrix/Matrix.java

结果

这里写图片描述

四.矩阵乘法

已知稀疏矩阵A(m1× n1)和B(m2× n2),求乘积C(m1× n2)。
稀疏矩阵A、B、C 及它们对应的三元组表A.data、B.data、C.data如下图:

这里写图片描述

计算方法相比大家都知道,线性代数的简单运算,口诀是:A的第一行跟B的第一列分别对应相乘,然后相加;往后依次A的第一行与B的第二列;等等。

这里写图片描述

 /**
     * 两稀疏矩阵相乘。
     * 前提:1.矩阵元素能够相乘
     *       2.一个矩阵的列等于另一个矩阵的行
     * 原理:假设两矩阵M与N相乘,前提M的列M.col要等于N的行N.row(反之亦可)
     * 得到结果矩阵Q, Q.row=M.row, Q.col = N.col
     * 而且Q[i][j] += M[i][k] * N[k][j]  0<i<M.row,0<j<N.col,0<k<M.col或N.row
     */
    public Integer[][] multiMatrix(Integer[][] m, Integer[][] n){
        Integer[][] q = new Integer[m.length][n[0].length];
        for(int i=0;i<m.length;i++){
            for(int j=0;j<n[0].length;j++){
                int num = 0;
                for(int k=0;k<n.length;k++){
                    num += (m[i][k]==null?0:m[i][k]) * (n[k][j]==null?0:n[k][j]);
                }
                q[i][j] = num;
            }
        }
        //打印结果
        for(int i=0;i<q.length;i++){
            for(int j=0;j<q[0].length;j++){
                System.out.print(q[i][j]+" ");
            }
            System.out.println();
        }
        return q;
    }

完整代码见github

给一个矩阵计算的线上计算器:https://matrixcalc.org/zh/#%7B%7B1,1%7D,%7B2,2%7D%7D%2A%7B%7B1,1%7D,%7B2,2%7D%7D

结果

这里写图片描述

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是稀疏矩阵三元组存储及快速转置的C语言代码: ```c #include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 typedef struct{ int i; int j; int e; }Triple; typedef struct{ Triple data[MAXSIZE + 1]; int mu, nu, tu; }TSMatrix; int TransposeSMatrix(TSMatrix M, TSMatrix *T){ int col, t, q; T->mu = M.nu; T->nu = M.mu; T->tu = M.tu; if (T->tu){ q = 1; for (col = 1; col <= M.nu; col++){ for (t = 1; t <= M.tu; t++) if (M.data[t].j == col){ T->data[q].i = M.data[t].j; T->data[q].j = M.data[t].i; T->data[q].e = M.data[t].e; q++; } } } return 1; } int main(){ TSMatrix M, T; int i, j, k; printf("请输入矩阵的行数,列数,非零元素个数并输入三元组:\n"); scanf("%d %d %d", &M.mu, &M.nu, &M.tu); for (i = 1; i <= M.tu; i++) scanf("%d %d %d", &M.data[i].i, &M.data[i].j, &M.data[i].e); printf("原始矩阵:\n"); for (i = 1; i <= M.mu; i++){ for (j = 1; j <= M.nu; j++){ k = 1; while (k <= M.tu && M.data[k].i <= i){ if (M.data[k].i == i && M.data[k].j == j){ printf("%d ", M.data[k].e); break; } k++; } if (k > M.tu) printf("0 "); } printf("\n"); } TransposeSMatrix(M, &T); printf("转置矩阵:\n"); for (i = 1; i <= T.mu; i++){ for (j = 1; j <= T.nu; j++){ k = 1; while (k <= T.tu && T.data[k].i <= i){ if (T.data[k].i == i && T.data[k].j == j){ printf("%d ", T.data[k].e); break; } k++; } if (k > T.tu) printf("0 "); } printf("\n"); } return 0; } ``` 这是一个简单的实现,对于更大规模的稀疏矩阵,我们可以使用更高效的算法来进行转置操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值