【稀疏矩阵乘法】行索引稀疏矩阵乘法改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

智能推荐

古典密码技术_了解古典密码的算法 了解古典密码的详细步骤 掌握古典密码的基本原理-程序员宅基地

文章浏览阅读7.4k次,点赞4次,收藏18次。古典密码技术古典密码是密码学中的其中一个类型,其大部分加密方式都是利用替换式密码或移项式密码,有时则是两者的混合。其于历史中经常使用,但在现代由于计算机的出现,使得古典密码解密已经不再困难,已经很少使用,大部分的已经不再使用了。古典密码技术根据其基本原理大体可以分为两类:替换密码技术和换位密码技术。替换密码技术替换密码技术是基于符号替换的密码技术。一般有单字符单表替换密码技术、单字符多表..._了解古典密码的算法 了解古典密码的详细步骤 掌握古典密码的基本原理

liunx中ls -la-程序员宅基地

文章浏览阅读1.4w次,点赞2次,收藏7次。ls 列出目录(文件夹)中的文件和子目录-l 长格式列出-a 显示所有文件,包括隐藏文件和目录(所有以“.”为开始的文件和目录为隐藏文件)所以ls -la 是列出当前目录中的所有文件和目录,包括隐藏文件和目录但不是查看文件里面的内容,查看文件的里的内容用的是more,less,cat等命令_ls -la

Java pta 面对对象(下)_定义一个车辆类(vehicle)和它的一个子类——客车类(bus),具体要求如下:(1)车辆类v-程序员宅基地

文章浏览阅读984次,点赞21次,收藏18次。Java pta 面对对象(下)7-1 定义一个车辆类和它的一个子类——客车类7-2 jmu-Java-03面向对象基础-04-形状-继承_定义一个车辆类(vehicle)和它的一个子类——客车类(bus),具体要求如下:(1)车辆类v

图像处理中常用的彩色模型_cmy-程序员宅基地

文章浏览阅读3.6w次,点赞10次,收藏68次。颜色模型就是描述用一组数值来描述颜色的数学模型。在彩色图像处理中,选择合适的彩色模型是很重要的。从应用的角度来看,彩色模型可分为两类:面向硬件设备的彩色模型面向视觉感知的彩色模型_cmy

计算机毕业设计 SSM+Vue健身房系统 健身会员管理系统 健身俱乐部管理系统 健身会所管理系统 健身预约教练管理系统Java Vue MySQL数据库 远程调试 代码讲解_ssm vue健身管理系统源码百度网盘-程序员宅基地

文章浏览阅读146次。计算机毕业设计 SSM+Vue健身房系统 健身会员管理系统 健身俱乐部管理系统 健身会所管理系统 健身预约教练管理系统_ssm vue健身管理系统源码百度网盘

LangChain - Chain-程序员宅基地

文章浏览阅读771次,点赞20次,收藏25次。1、概览为什么我们需要链?2、快速入门 (Get started) - Using `LLMChain`多个变量 使用字典输入在 `LLMChain` 中使用聊天模型:3、异步 API4、不同的调用方法`__call__`调用仅返回输出键值 return_only_outputs只有一个输出键 run只有一个输入键5、自定义chain6、调试链 (Debugging chains)7、从 LangChainHub 加载8、添加记忆(state)9、序列化将chain 保存到

随便推点

《前端框架开发技术》HTML+CSS+JavaScript 制作个人简历模板-程序员宅基地

文章浏览阅读790次。个人网页设计、‍♂️个人简历制作、简单静态HTML个人网页作品、个人介绍网站模板 、等网站的设计与制作。个人网页设计网站模板采用DIV CSS布局制作,网页作品有多个页面,如 :个人介绍(文字页面)、我的作品(图片列表)、个人技能(图文页面)、在线留言(表单页面)CSS样式方面网页整体采用左右布局结构,制作了网页背景图片,导航区域每个导航背景色不同,导航背景色与页面背景呼应。 一套A+的网页应该包含 (具体可根据个人要求而定)网站布局方面:计划采用目前主流的、能兼容各大...

TailwindCSS为前端开发者带来了什么?_tailwindcss的优点-程序员宅基地

文章浏览阅读2.3k次。什么是Tailwind CSS?Tailwind CSS是一个功能类优先的CSS框架,它集成了flex、text-center这样的类,Tailwind CSS希望实现的是开发者无需离开HTML页面,即可快速创建出各种样式效果。Tailwind CSS相较于其他CSS框架有什么优势?优势1:Tailwind CSS类名具有较好的语义化传统的语义化类名是CSS难以维护的重要原因,也就是说起名很麻烦,但是Tailwind CSS的语义化类名可以很好的解决这个问题,例如:text-lg:表示一个_tailwindcss的优点

python 设置全局变量-程序员宅基地

文章浏览阅读8.2k次,点赞3次,收藏14次。python 设置全局变量,跨文件使用_python 设置全局变量

遍历磁盘_遍历所有移动硬盘-程序员宅基地

文章浏览阅读1.2k次。#include "stdafx.h"#include int main(){ TCHAR buf[MAX_PATH] = {}; int nDriveType; //1 获取磁盘盘符 GetLogicalDriveStrings(MAX_PATH, buf); TCHAR* pDrives = buf; while (_遍历所有移动硬盘

element-ui的隐藏组件el-scrollbar的使用(解决原生滚动条没有隐藏的问题 高宽设置)_el-scrollbar__wrap-程序员宅基地

文章浏览阅读1.3w次,点赞9次,收藏27次。element-ui的官网页面使用的这个滚动条,但是在官网文档中没有介绍这个组件。在vue+elementui搭建的前端项目中使用这个el-scrollbar组件。在项目中使用这个组件时由于各层的样式没有设置好,可能会显示出原生的滚动条,特此记录。搭建脚手架项目,安装element-ui插件按需引入需要的组件import Vue from 'vue'import { Scrollbar} from 'element-ui'Vue.use(Scrollbar)使用<_el-scrollbar__wrap

LabVIEW开发TDS1000 和TDS2000 系列泰克示波器_泰克示波器 labview-程序员宅基地

文章浏览阅读392次,点赞2次,收藏3次。泰克示波器是经常用到的工具,一般手动操作即可,但有时候也要集成到系统中,需要程控。这时候先要下载厂家提供的例子,了解LabVIEW的demo。示波器的功能挺多的,手册也是几百上千页,需要哪些功能,查找对应的部分就可以了。附件给出了LabVIEW的demo,需要的时候可以下载。手册可以到官网上下载,如果查不到,也可以联系厂家在线的技术,他们也会及时提供的。这是LabVIEW的一个功能介绍,更多的使用方法与开发案例,欢迎登录官网,了解更多信息。根据通讯协议的相关的说明,编写了适合项目的程序。_泰克示波器 labview

推荐文章

热门文章

相关标签