1、稀疏矩阵的存储与表示

只存储稀疏矩阵中极少数的非零元素,采用一个三元组<row,column,value>来唯一确定一个矩阵元素;因此,稀疏矩阵可用一个三元组数组来表示。另外,还需要存储原矩阵的行数、列数和非零元素个数。

2、代码实现

快速转置和矩阵乘法函数中都用到了两个辅助数组

+ rowSize[] 存储矩阵每一行非零元素的个数,下标表示行号
+ rowStart[] 存储矩阵每一行非零元素在三元组数组存储的起始位置,下标表示行号

因为矩阵的存储是按照从左到右从上到下元素的顺序存储的,利用以上两个辅助数组可以避免多次重复访问三元组数组。
+ SparseMatrix.h

/** @author:Curya* @time:2017-09-08* @theme:稀疏矩阵————包括矩阵转置、矩阵乘法、矩阵加法* */
#ifndef SPARSEMATRIX_H
#define SPARSEMATRIX_H
#include <iostream>
#include <cstdlib>using namespace std;template<class T>
struct Trituple {int row;    //行号int col;    //列号T value;    //非零元素的值Trituple<T>& operator = (const Trituple<T>& x){row = x.row;col = x.col;value = x.value;return *this;}
};template<class T>
class SparseMatrix
{//输入输出运算符重载template<class U>friend ostream& operator << (ostream& out, const SparseMatrix<U>& myMatrix);template<class U>friend istream& operator >> (istream& in, SparseMatrix<U>& myMatrix);
private:int rowCnts;int colCnts;int valueCnts;Trituple<T> *sparseMatrix;int maxCnts;
public:SparseMatrix(int sz = 100);                         //构造函数SparseMatrix(SparseMatrix<T>& x);                   //复制构造函数~SparseMatrix();                                   //析构函数SparseMatrix<T>& operator = (const SparseMatrix<T>& x); //赋值运算符重载(不加const报错)SparseMatrix<T> transpose();                        //矩阵转置SparseMatrix<T> fastTranspose();                    //快速矩阵转置SparseMatrix<T> addMatrix(SparseMatrix<T>& b);      //矩阵加法SparseMatrix<T> mulMatrix(SparseMatrix<T>& b);      //矩阵乘法
};template<class T>
SparseMatrix<T>::SparseMatrix(int sz)
{maxCnts = sz;if(maxCnts < 1) {cerr << "matrix init error!" << endl;exit(1);}sparseMatrix = new Trituple<T>[maxCnts];if(sparseMatrix == NULL) {cerr << "memory alloc error!" << endl;exit(1);}rowCnts = 0;colCnts = 0;valueCnts = 0;
}template<class T>
SparseMatrix<T>::SparseMatrix(SparseMatrix<T>& x)
{rowCnts = x.rowCnts;colCnts = x.colCnts;valueCnts = x.valueCnts;maxCnts = x.maxCnts;sparseMatrix = new Trituple<T>[maxCnts];if(sparseMatrix == NULL) {cerr << "memory alloc error!" << endl;exit(1);}for(int i = 0; i < valueCnts; ++i) {sparseMatrix[i] = x.sparseMatrix[i];}
}template<class T>
SparseMatrix<T>::~SparseMatrix()
{delete []sparseMatrix;
}template<class T>
SparseMatrix<T>& SparseMatrix<T>::operator=(const SparseMatrix<T>& x)
{if(this == &x)return *this;rowCnts = x.rowCnts;colCnts = x.colCnts;valueCnts = x.valueCnts;maxCnts = x.maxCnts;if(sparseMatrix == NULL) {cerr << "memory alloc error!" << endl;exit(1);}for(int i = 0; i < valueCnts; ++i) {sparseMatrix[i] = x.sparseMatrix[i];}return *this;
}//效率低
template<class T>
SparseMatrix<T> SparseMatrix<T>::transpose()
{SparseMatrix<T> trans(100);trans.rowCnts = this->colCnts;trans.colCnts = this->rowCnts;trans.valueCnts = this->valueCnts;if(this->valueCnts > 0) {int k, i, currentPtr = 0;for(k = 0; k < this->colCnts; ++k) {for(i = 0; i < this->valueCnts; ++i) {if(this->sparseMatrix[i].col == k) {trans.sparseMatrix[currentPtr].row = k;trans.sparseMatrix[currentPtr].col = this->sparseMatrix[i].row;trans.sparseMatrix[currentPtr].value = this->sparseMatrix[i].value;currentPtr++;}}}}return trans;
}template<class T>
SparseMatrix<T> SparseMatrix<T>::fastTranspose()
{//两个辅助数组int *rowSize = new int[colCnts];        //统计转置后各行元素的个数(转置前各列元素个数)int *rowStart = new int[colCnts];       //计算转置后,每行第一个非零元素存放的位置//Tips://(1)总的元素个数已知//(2)转置之后各行元素已知//==>可以计算转之后每行的第一个非零元素在总的矩阵(一维数组)存放位置//eg.假设一共有6个元素,//转置之前存储顺序为(1,2)、(2,1)、(3,0)、(3,2)、(4,2)、(4,3)//转置之后的存储顺序(0,3)、(1,2)、(1,4)、(2,1)、(2,3)、(3,4)//可以计算,第一行非零元素个数c0=1;第二行c1=2;第三行c2=2;第四行c3=1//第一行第1个非零元素存放位置为0;第二行(0+c0)=1;第三行(1+c1)=3;第四行(3+c2)=5SparseMatrix<T> trans(100);             //存放矩阵转置后的结果trans.colCnts = rowCnts;trans.rowCnts = colCnts;trans.valueCnts = valueCnts;if(valueCnts > 0) {int i, j;for(i = 0; i < colCnts; ++i)    rowSize[i] = 0;for(i = 0; i < valueCnts; ++i)  rowSize[sparseMatrix[i].col]++;rowStart[0] = 0;for(i = 1; i < colCnts; ++i)rowStart[i] = rowStart[i - 1] + rowSize[i - 1];for(i = 0; i < valueCnts; ++i) {//查询该元素(转置后行号:sparseMatrix[i].col)应该存放的位置jj = rowStart[sparseMatrix[i].col];trans.sparseMatrix[j].row = sparseMatrix[i].col;trans.sparseMatrix[j].col = sparseMatrix[i].row;trans.sparseMatrix[j].value = sparseMatrix[i].value;//原来应该存放的位置已占用,将其+1rowStart[sparseMatrix[i].col]++;}}delete[] rowSize;delete[] rowStart;return trans;
}template<class T>
SparseMatrix<T> SparseMatrix<T>::addMatrix(SparseMatrix<T>& b)
{SparseMatrix<T> addResult;if(this->rowCnts != b.rowCnts || this->colCnts != b.colCnts)return addResult;addResult.colCnts = colCnts;addResult.rowCnts = rowCnts;addResult.valueCnts = 0;int i = 0, j = 0;//思路与一元多项式计算一致(数据有序存储)int index_a, index_b;           //根据三元组元素计算的该元素在数组中的索引位置while(i < this->valueCnts && j < this->valueCnts) {index_a = this->sparseMatrix[i].row * colCnts + this->sparseMatrix[i].col;index_b = b.sparseMatrix[j].row * colCnts + b.sparseMatrix[j].col;if(index_a < index_b) {addResult.sparseMatrix[addResult.valueCnts] = this->sparseMatrix[i];i++;} else if(index_a > index_b) {addResult.sparseMatrix[addResult.valueCnts] = b.sparseMatrix[j];j++;} else {addResult.sparseMatrix[addResult.valueCnts] = this->sparseMatrix[i];addResult.sparseMatrix[addResult.valueCnts].value = this->sparseMatrix[i].value + b.sparseMatrix[j].value;i++;j++;}addResult.valueCnts++;}//复制剩下的元素for(; i < valueCnts; ++i) {addResult.sparseMatrix[addResult.valueCnts] = this->sparseMatrix[i];addResult.valueCnts++;}for(; j < valueCnts; ++j) {addResult.sparseMatrix[addResult.valueCnts] = b.sparseMatrix[j];addResult.valueCnts++;}return addResult;
}//Tips:A[i][k]*B[k][j]
//对A矩阵进行遍历,取得一个A[i][k],根据列号k,到矩阵B抽取所有行号为k的元素
//在B矩阵的存储中,同行号的相邻存储,因此只需要知道该行元素存储的起始位置以及元素的个数
//建立两个辅助矩阵:
//rowSize[]===>存储每一行的元素个数
//rowStart[]===>存储每一行元素存储的起始位置
template<class T>
SparseMatrix<T> SparseMatrix<T>::mulMatrix(SparseMatrix<T>& b)
{SparseMatrix<T> mulResult;if(this->colCnts != b.rowCnts) {cerr << "cannot multiply!" << endl;return mulResult;}if(this->valueCnts == 100 || b.valueCnts == 100) {cerr << "space needed in a or b" << endl;return mulResult;}mulResult.rowCnts = this->rowCnts;mulResult.colCnts = b.colCnts;//辅助矩阵int *rowSize = new int[b.rowCnts];          //B矩阵每一行所含元素个数int *rowStart = new int[b.rowCnts + 1];     //B矩阵每一行第一个元素开始位置T *tmp = new T[b.colCnts];//辅助矩阵数据初始化for(int i = 0; i < b.rowCnts; ++i)rowSize[i] = 0;for(int i = 0; i < b.valueCnts; ++i)rowSize[b.sparseMatrix[i].row]++;rowStart[0] = 0;for(int i = 1; i <= b.rowCnts; ++i)rowStart[i] = rowStart[i - 1] + rowSize[i - 1];//对矩阵A进行遍历int current = 0;                        //遍历指针int lastInResult = -1;int rowA, colA, colB;                   //当前处理元素的行号、列号信息while(current < this->valueCnts) {rowA = this->sparseMatrix[current].row;//tmp用来暂存当前处理行的结果,初始化为0for(int i = 0; i < b.colCnts; ++i)tmp[i] = 0;//对A矩阵第rowA行进行处理,该循环每次处理A矩阵一行数据与B矩阵一列数据对应的相乘while(current < this->valueCnts && this->sparseMatrix[current].row == rowA) {//获取当前A矩阵元素的列号,用于获取对应操作的B矩阵元素colA = this->sparseMatrix[current].col;for(int i =  rowStart[colA]; i < rowStart[colA + 1]; ++i) {//获取当前B矩阵元素列号,将结果存储到以当前B矩阵元素列号为下标的tmp中colB = b.sparseMatrix[i].col;tmp[colB] += this->sparseMatrix[current].value * b.sparseMatrix[i].value;}current++;}//上一个while循环结束==>一行处理结束,将临时存储数据保存到结果中//将临时存储的tmp转储到矩阵相乘结果矩阵(mulResult)中for(int i = 0; i < b.colCnts; ++i) {if(tmp[i] != 0) {lastInResult++;mulResult.sparseMatrix[lastInResult].row = rowA;mulResult.sparseMatrix[lastInResult].col = i;mulResult.sparseMatrix[lastInResult].value = tmp[i];}}}mulResult.valueCnts = lastInResult + 1;delete []rowSize;delete []rowStart;delete []tmp;return mulResult;
}template<class T>
ostream& operator << (ostream & out, const SparseMatrix<T>& myMatrix)
{out << "rowCnts:" << myMatrix.rowCnts << " "<< "colCnts:" << myMatrix.colCnts << " "<< "nonZero valueCnts:" << myMatrix.valueCnts << endl;for(int i = 0; i < myMatrix.valueCnts; ++i) {out << "M[" << myMatrix.sparseMatrix[i].row<< "][" << myMatrix.sparseMatrix[i].col<< "] = " << myMatrix.sparseMatrix[i].value << endl;}return out;
}template<class T>
istream& operator >> (istream & in, SparseMatrix<T>& myMatrix)
{cout << "input numbers of rowCnts, columnCnts and valueCnts" << endl;in >> myMatrix.rowCnts >> myMatrix.colCnts >> myMatrix.valueCnts;if(myMatrix.valueCnts > 100) {cerr << "number of terms overflow!" << endl;exit(1);}for(int i = 0; i < myMatrix.valueCnts; ++i) {cout << "input row, column and value of term " << i << ": ";in >> myMatrix.sparseMatrix[i].row>> myMatrix.sparseMatrix[i].col>> myMatrix.sparseMatrix[i].value;}return in;
}#endif // SPARSEMATRIX_H
  • test.cpp
#include <iostream>
#include "SparseMatrix.h"int main(int argc, char **argv)
{
//  SparseMatrix<int> myMatrix;
//  SparseMatrix<int> trans;
//  cin >> myMatrix;
//  cout << myMatrix;
//  trans = myMatrix.transpose();       //SparseMatrix类的赋值运算符重载函数不添加const,该语句报错
//  cout << trans;
//  trans = trans.fastTranspose();
//  cout << trans;
//  trans = trans.addMatrix(trans);
//  cout << trans;SparseMatrix<int> a, b;cin >> a;cin >> b;cout << a;cout << b;cout << a.mulMatrix(b);return 0;
}//tips:问题解释参见下链接
//应该是因为,transpose函数返回值是一个临时对象,
//赋值运算符重载函数形参是引用类型(引用传递),即引用形参是它对应实参的别名
//https://stackoverflow.com/questions/20247525/about-c-conversion-no-known-conversion-for-argument-1-from-some-class-to/*
Add function
10 10 9
0 2 2
1 0 3
1 3 -11
2 3 -6
3 5 -17
4 1 9
4 4 19
5 3 -8
5 6 -52Multiply function
3 4 7
0 0 10
0 2 5
0 3 7
1 0 2
1 1 1
2 0 3
2 2 4
4 2 6
0 0 2
1 0 4
1 1 8
2 1 14
3 0 3
3 1 5
*/

稀疏矩阵的存储以及转置、加法、乘法操作实现相关推荐

  1. 用三元组存储稀疏矩阵,实现其快速转置c语言代码,稀疏矩阵三元组表快速转置(C语言实现)...

    本来准备昨天下午写的,但是因为去参加360众测靶场的考核耽搁了,靶场的题目还是挺基础的. 继续学习吧. 使用黑色墨水在白纸上签名就像由像素点构成的稀疏矩阵.如图4所示. 图4手写体签名 [问题]请将以 ...

  2. 计算机底层加法/乘法实现

    计算机底层加法/乘法实现 存储方式 原理 加法 乘法 除法 代码实现 加法 乘法 存储方式 计算机底层中存放数字使用二进制形式,负数使用补码(反码+1)来存放. 原理 加法 两个二进制的相加结果是用一 ...

  3. C语言实现稀疏矩阵存储和转置

    稀疏矩阵存储和转置 稀疏矩阵是矩阵中一种特别的矩阵,主要特点是:非零元素占矩阵所有元素的比例极少.那么,对于这种矩阵的存储,就存在很多很节省空间的方式,核心要点也就是舍弃那些无用元素即零元素,下面将以 ...

  4. python稀疏矩阵的存储与表示

    参考链接: https://blog.csdn.net/bitcarmanlee/article/details/52668477 https://blog.csdn.net/wangjian1204 ...

  5. c语言三元组稀疏矩阵的转置实验报告,稀疏矩阵三元组实现矩阵转置算法实验报告.doc...

    稀疏矩阵三元组实现矩阵转置算法实验报告.doc 1实验三稀疏矩阵的三元组表示实现矩阵转置算法学院专业班学号姓名一.实习目的1掌握稀疏矩阵的三元组顺序表存储表示:2掌握稀疏矩阵三元组表示的传统转置算法的 ...

  6. java 乘法_java大数加法乘法

    java大数加法乘法 前言 正常情况下我们调用加法乘法使用符号就行了,但是如果超出限制了,那就只能调用BigDecimal里面的函数了,但是有的时候oj考察的就是希望自己实现,所以就可以采用别的方法. ...

  7. 手机内存卡转化linux,Android 往手机内存卡上存储用户名与密码的操作

    当大家 用Android 应用 操作时,会发现有很多应用要登陆名和密码,而且,它们都能记住密码,当你退出 ,再次登陆时,你们帐号密码会自动添加上去. 例: 布局文件 相信都能做出来 就不一一介绍 了. ...

  8. python乘法函数_Python中列表与元组的乘法操作示例

    本文实例讲述了Python中列表与元组的乘法操作.分享给大家供大家参考,具体如下: 直接上code吧,还可以这么玩儿 列表乘法: li=[1,] li=li*3 print(li) out: [1, ...

  9. pytorch中的乘法操作

    pytorch中提供了多种函数用于乘法操作,不同函数,功能有什么不一样呢? torch.mul multiply是mul的别名,与mul用法一致 torch.mul(input, other, *, ...

最新文章

  1. 用PaddlePaddle打比赛!
  2. linux opensuse 集成工具yast 使用方法
  3. 静态Web开发 JQuery
  4. 在vs2005中安装boost库
  5. 小眼睛有多惨?美颜都懒得救你......
  6. 决策树可视化保姆级教程
  7. PostgreSQL9.6+PostGIS2.3学习笔记(一)导入shp文件
  8. 嵌入式Linux开发板上NFS文件系统的使用【ZT】
  9. linux系统的文件系统tmpfs,linux里tmpfs文件系统
  10. SimpleDateFormat线程不安全及解决方式
  11. 第 7 章 Neutron - 082 - 将 instance 连接到 first_local_net
  12. 家庭版完全免费,下面的注册码为:avast! 4 pro(专业版)的
  13. gooflow的流程设计
  14. 撬动百亿台设备,让物联网“造”起来!
  15. 如何用MEGA-X构建进化树
  16. 密码学的发展(第二篇:恩尼格码机)
  17. 纽约州立石溪分校计算机科学排名,美国纽约州立大学石溪分校排名_2019纽约州立大学石溪分校排名(USNews排名)...
  18. CEYE平台使用简介
  19. leetcode每日一题 911在线选举
  20. 感谢这一年的尚不如愿,这是下一年必须努力的理由

热门文章

  1. CDH部署Livy服务
  2. python--PyCHarm里代码整体向左/右缩进
  3. RBA 7.0 责任商业联盟行为准则改版重点解析
  4. 只为让你听见更好的声音 吉利缤瑞音响升级牧童套餐喇叭
  5. 提高你的被动收入——基金投资
  6. IC设计——EDA软件篇——xcelium
  7. NODEMCU介绍与使用
  8. 手写文字识别软件哪个好?安利这三款
  9. js中判断变量不为空或null或“”
  10. 西雅图秋招来了, 哪家公司给应届生的工资最高?