【稀疏矩阵乘法】行索引稀疏矩阵乘法改c++版(严蔚敏版)_行索引建立稀疏矩阵-程序员宅基地

技术标签: 算法  代码  稀疏矩阵  矩阵乘法  实现  数据结构  

行索引稀疏矩阵乘法(严蔚敏版)

原理

行索引稀疏矩阵查找某一列的元素没那么方便,所以在做矩阵乘法时(这里以M乘N=Q为例),严书的做法是:在求Q的某一行的值是,用M的一行去遍历N的每一行,对结果中同列的值进行累加,最后稀疏化存入Q的当前行中,这个过程还原成正常矩阵比较容易理解:
求Q(2,2)的第一行时,肯定是M的第一行和N的第一列逐乘再累加,然后再M的第一行和N的第二列逐乘累加
M(2,3)* N(3,2):
矩阵相乘
直接算的话就是:
Q[1,1] = 1*1 + 2*0 + 3*1 = 1+0+3 = 4
Q[1,2] = 1*0 + 2*1 + 3*1 = 0+2+3 = 5
这回我们直接同时求两列的值,其实就是改变一下计算顺序:
改变计算顺序
这个就相当于严书代码中ctemp的作用,只不过ctemp是直接累加.

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int MAX_E = 1e+4+5, MAX_R = 105;

//严版特色,下标从1开始
struct Triple{
    int i,j,e;};
struct RLSMatrix{
    
    Triple data[MAX_E];
    int rpos[MAX_R];//行首索引, rpos[i]指向第i行中的首元素在data中的序号, 则rpos[i+1]-1指向第i行中最后一个非0元素在N.data中的序号.
    int rows, cols, elems;
};

int ctemp[MAX_R];//Q的第i行元素结果累加器,算完一行就压缩存储进Q.data中


RLSMatrix mul(RLSMatrix M, RLSMatrix N){
    
    RLSMatrix Q;
    Q.rows = M.rows;Q.cols = N.cols;Q.elems = 0;
    if(M.elems * N.elems != 0){
                                  // Q是非零矩阵
        for(int arow = 1; arow <= M.rows; arow++){
    
            memset(ctemp, 0, sizeof(ctemp));              //到了下一行,清零
            Q.rpos[arow] = Q.elems+1;                  //新一行的行首索引是当前data中元素个数+1,从该处继续向data中存三元组

            int tp;      //用tp指向data中该行行末的下一个位置,方便遍历
            if(arow < M.rows) tp = M.rpos[arow+1];    //如果不是最后一行, tp指向下一行行首
            else tp = M.elems+1;   //最后一行, tp直接指向data中最后一个+1

            for(int p = M.rpos[arow];p < tp; p++){
      //对当前行找到的每一个非零元
                int brow = M.data[p].j;     //找到对应元在N中的行号(M中某行第三列的元素, 肯定和N中第三行某列的元素相乘)
                int t;//和tp同样的套路
                if(brow < N.rows) t = N.rpos[brow+1];
                else t = N.elems+1;

                for(int q = N.rpos[brow]; q < t; q++){
    //这里不是直接算出M的某行乘N的某列的值
                    //而是用M的某行,去遍历N的所有行,然后对每行的应该在同列的值进行累加
                    int ccol = N.data[q].j;
                    ctemp[ccol] += M.data[p].e * N.data[q].e;//累加器
                }
            }//求得Q中第crow(=arow)行的非零元

            for(int ccol = 1; ccol <= Q.cols; ++ccol){
    //用M的一行遍历完了整个N矩阵
                if(ctemp[ccol]){
    
                    Q.data[++Q.elems] = {
    arow, ccol, ctemp[ccol]};//压缩存储
                }
            }
        }
    }
    return Q;
}

RLSMatrix makeMat(){
    
    /*
     * 输入rows, cols, 三元组个数
     * 输入三元组
     */
    RLSMatrix A;
    cin>>A.rows>>A.cols>>A.elems;
    for(int i = 1;i <= A.elems;i++){
    
        int x,y,e;
        cin>>x>>y>>e;
        A.data[i] = {
    x,y,e};
    }

    /*
     根据乘法中这段代码写的初始化rpos数组:
         int tp;      //用tp指向data中该行行末的下一个位置,方便遍历
         if(arow < M.rows) tp = M.rpos[arow+1];    //如果不是最后一行, tp指向下一行行首
         else tp = M.elems+1;   //最后一行, tp直接指向data中最后一个+1
         for(int p = M.rpos[arow];p < tp; p++) ...
        可以看出如果某行没有元素,则让tp = M.rpos[arow]则可不进行遍历,也就是M.rpos[arow] = M.rpos[arow+1]
        而当最后几行为空时,并不会执行else tp = M.elems+1;这时应该把rpos最后几行空的填成M.elems+1
     */

    int row = 1;
    for(int e = 1;e <= A.elems; e++){
    
        int arow = A.data[e].i;
        while(row <= arow){
    
            A.rpos[row++] = e;
        }
    }
    while(row <= A.rows){
    //如果最后几行没有元素,让索引指到elems+1的位置
        A.rpos[row++] = A.elems+1;
    }
    return A;
}

void printMat(RLSMatrix A){
    
    cout<<"rows:"<<A.rows<<" cols:"<<A.cols<<" elems:"<<A.elems<<endl;
    cout<<"-------------------------"<<endl;
    cout<<"data:"<<endl;
    for(int i = 1;i <= A.elems;i++) {
    
        cout<<setw(4)<<A.data[i].i<<setw(4)<<A.data[i].j<<setw(4)<<A.data[i].e<<endl;
    }
    cout<<"-------------------------"<<endl;
    cout<<"rpos: ";
    for(int j = 1;j <= A.rows; j++){
    
        cout<<A.rpos[j]<<' ';
    }
    cout<<endl<<endl;
}

int main(){
    
    ios::sync_with_stdio(false);
    RLSMatrix A = makeMat();
    printMat(A);
    RLSMatrix B = makeMat();
    printMat(B);
    RLSMatrix C = mul(A, B);
    printMat(C);
    return 0;
}
/*
 严书上的例子
 3 4 4
 1 1 3
 1 4 5
 2 2 -1
 3 1 2

 4 2 4
 1 2 2
 2 1 1
 3 1 -2
 3 2 4
 */

结果

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ZAX130/article/details/103372269

智能推荐

NFC技术演进_nfc的演进-程序员宅基地

文章浏览阅读289次。RF演进protocol 演进_nfc的演进

1.3 wait 和notify 原理_wait 和 notify原理-程序员宅基地

文章浏览阅读384次。wait 和notify 是实现线程之间的协同工作,必须结合synchronized使用,wait 释放锁,notify 不释放锁(但是此时会通知在等待的wait,该notify完全执行完毕,才真正释放锁)public class DemoThread18{ //原子类 private volatile List&lt;String&gt; list = new ArrayList..._wait 和 notify原理

谷歌又出浏览器了Google Chrome_谷歌浏览器 我是人类-程序员宅基地

文章浏览阅读601次。相信大部分 做ui的朋友 都非常痛恨一件事情 就是程序以及css和不同浏览器的兼容问题,我就奇怪了google你不好好的做你的搜索引擎,弄什么浏览器呀,本让现在 作东西考虑各个浏览器兼容 已经够累的,你还真会添乱。本来做你就做也无所谓,还花那么大力气推广,要不说你有钱,有了用户群,写东西就不得不考虑你了,大哥我们这些 闷头写程序的不容易,我们还要养家户口呢,你就别添乱了行不行。 _谷歌浏览器 我是人类

微信公众号在线选房电子选车位房地产云开盘线上大屏幕抢房系统-程序员宅基地

文章浏览阅读551次,点赞18次,收藏9次。前端演示咨询客服:

MAKO Vimba2.0安装教程和qt中调用Vimba相机_vimba viewer-程序员宅基地

文章浏览阅读6.4k次,点赞7次,收藏29次。一、MAKO Vimba2.0安装教程1. 打开Vimba2.0安装软件,用户可到大恒官网下载最新驱动。2.选择选项Application Development和安装路径,注意:安装路径中不要存在空格。然后,点击Star,开始安装。 3.勾选Install Vimba Drivers,然后,点击Exit退出。4.接下来继续安装,勾选-选择“安装”,重复操作..._vimba viewer

【Linux4.1.12源码分析】协议栈报文接收之传输层处理分析(UDP)___udp4_lib_rcv-程序员宅基地

文章浏览阅读3k次。UDP报文的处理入口是udp_rcv函数,该函数是在ip_local_deliver_finish函数中被调用的。1、udp_rcv函数int udp_rcv(struct sk_buff *skb){ return __udp4_lib_rcv(skb, &udp_table, IPPROTO_UDP);}2、__udp4_lib_rcv函数int __udp4_lib_rcv___udp4_lib_rcv

随便推点

HOG特征——行人识别_hog特征识别行人 peopledetector=vision.peopledetector; i=-程序员宅基地

文章浏览阅读1.8k次,点赞4次,收藏24次。HOG特征简介HOG 全称为 Histogram of Oriented Gradients ,即方向梯度的直方图。HOG 是由 Navneet Dalal & Bill Triggs 在 CVPR 2005发表的论文中提出来的,目的是为了更好的解决行人检测的问题。先来把这几个字拆开介绍,首先,梯度的概念和计算梯度的方法已经在前一篇文章中介绍了,方向梯度就是说梯度的方向我们也要利用上,..._hog特征识别行人 peopledetector=vision.peopledetector; i=imread(

Spring Cloud 微服务的安全保护_springboot微服务安全-程序员宅基地

文章浏览阅读2.8k次,点赞2次,收藏9次。上一篇文章中介绍了如何使用Spring Cloud搭建微服务,在本文中讲讲如何对微服务进行安全保护。在Spring Cloud中对应用进行安全保护通常使用Spring Security,这种方式集成起来非常简单而且很容易扩展现有的应用场景。在分布式环境中Spring Security使用Spring Session和Redis来共享会话。共享会话可以将在微服务网关中登录的用户验证信息传递到系统..._springboot微服务安全

生物信息学中两种常用的文本文件_.fa.gz-程序员宅基地

文章浏览阅读961次。通过自学《碱基矿工》[http://mp.weixin.qq.com/mp/homepage?__biz=MzAxOTUxOTM0Nw==&hid=1&sn=d945cf61bd86e85724e146df42af5bcc&scene=18#wechat_redirect]下面分别介绍这两种格式FASTAFASTA常作为存储有顺序的序列数据的文件后缀,包括我们常用的..._.fa.gz

【centos安装mysql服务器并开启远程访问】_centos 查看 mysql 远程连接-程序员宅基地

文章浏览阅读1k次。centos安装mysql如果设置的密码太简单了会报错( ERROR 1819 (HY000): Your password does not satisfy the current policy requirements)解决方案如下:登录mysql执行:第一个密码强度等级,第二个是密码长度设置为6位(如果你设置的是8位就不做修改)另外可以通过语句查看密码设置规则2 赋权所有远程ip都可以进行登录(如果未开放端口得需要去腾讯云或者阿里云官网实例防火墙与策略开启端口,mysql默认的_centos 查看 mysql 远程连接

Linux(centos)下Nginx+Keepalived集群环境搭建_linux搭建nginx+keepalived-程序员宅基地

文章浏览阅读299次。本人使用的环境是CentOS-6.4-x86_64-bin-DVD1.rar,nginx-1.6.2.tar.gz,keepalived-1.2.18.tar.gz。三台机器ip:192.168.1.123,192.168.1.124。同时关闭两台虚拟机的防火墙:chkconfig iptables off(永久关闭防火墙)..._linux搭建nginx+keepalived

WebMagic Java 爬虫的简单应用_webmagic没反应-程序员宅基地

文章浏览阅读2k次。前段时间做旅游本体的知识库,我和老师反应说景点之间关系太少了,导致整个图很稀疏。。“你去wiki上抓一批数据吧”,就这样被自己坑了。由于一直在用java做项目,ZWQ师兄推荐的是selenium,这个我想说真的很强大,还支持JS渲染,不过当我看到这篇的时候,我决定学一下WebMagic。项目中文文档地址:http://webmagic.io/docs/zh/这个项目很容易上手,只要_webmagic没反应