数据结构之 矩阵---稀疏矩阵
来源:互联网 发布:xmind 8 mac 注册码 编辑:程序博客网 时间:2024/06/05 12:45
在之前的学习中,写了矩阵的模板类。但是很多情况下,并不是每一个元素都是非零的,当一个矩阵中的非零元素的较少的时候,其实是存在着空间的浪费的,于是,应该采用稀疏矩阵的方式来进行数据的保存和运算。
11月1号将稀疏矩阵的内容写成了办完工状态,在注释中讨论到的顺序问题,还有待进一步的修改。
#ifndef _H_MY_SPARSE_MATRIX_H#define _H_MY_SPARSE_MATRIX_H#include <iostream>#include <vector>#include "myMatrix.cpp"template<class T>class sparseMatrix;template<class T>struct element{ int row; int col; T val; element(int r, int c, T v);};template<class T>element<T>::element(int r, int c, T v){ row = r; col = c; val = v;}template<class T>std::ostream& operator<<(std::ostream& out, sparseMatrix<T>& spm);template<class T>class sparseMatrix{public: sparseMatrix(void); sparseMatrix(myMatrix<T>& mat); sparseMatrix(int row, int col); sparseMatrix(sparseMatrix<T>& spm); ~sparseMatrix(); int cols(void){return m_col;} int rows(void){return m_row;} sparseMatrix<T>& operator=(sparseMatrix<T>& spm); void transpose(void); sparseMatrix<T> operator+(sparseMatrix<T>& spm); void output(std::ostream& out);private: int m_row; int m_col; std::vector<struct element<T> > vec_ele;};template<class T>sparseMatrix<T>::sparseMatrix(void){ m_row = -1; while(m_row <= 0) { std::cout<<"\t请输入你矩阵的行数:"; std::cin>>m_row; } m_col = -1; while(m_col <= 0) { std::cout<<"\t请输入你矩阵的列数:"; std::cin>>m_col; } int num = -1; while (num < 0) { std::cout<<"\t请输入非零元素的数目:"; std::cin>>num; } for (int ii = 0; ii < num; ii++) { int row = -1; int col = -1; T val; while (row <= 0 || row > m_row) { std::cout<<"\t请输入非零元素所在的行:"; std::cin>>row; } while (col <= 0 || col > m_col) { std::cout<<"\t请输入非零元素所在的行:"; std::cin>>col; } std::cout<<"\t请输入 "<<row<<" 行, "<<col<<" 列的非零元素:"; std::cin>>val; vec_ele.push_back(struct element<T>(row,col,val)); }}template<class T>sparseMatrix<T>::sparseMatrix(myMatrix<T>& mat){ m_row = mat.rows(); m_col = mat.cols(); vec_ele.clear(); for(int ii = 1; ii <= m_row; ii++) { for(int jj = 1; jj <= m_col; jj++) { if(mat(ii,jj) != 0) { vec_ele.push_back(struct element<T>(ii,jj,val)); } } }}template<class T>sparseMatrix<T>::sparseMatrix(int row, int col){ m_row = row; m_col = col; vec_ele.clear();}template<class T>sparseMatrix<T>::sparseMatrix(sparseMatrix<T>& spm){ m_col = spm.cols(); m_row = spm.rows(); vec_ele.clear(); for(std::vector<struct element<T> >::iterator it = spm.vec_ele.begin(); it != spm.vec_ele.end(); it++) { vec_ele.push_back(struct element<T>(it->row, it->col, it->val)); }}template<class T>sparseMatrix<T>::~sparseMatrix(){ vec_ele.clear();}template<class T>sparseMatrix<T>& sparseMatrix<T>::operator=(sparseMatrix<T>& spm){ if(this != &spm) { m_row = spm.rows(); m_col = spm.cols(); vec_ele.clear(); for(std::vector<struct element<T> >::iterator it = spm.vec_ele.begin(); it != spm.vec_ele.end(); it++) { vec_ele.push_back(struct element<T>(it->row, it->col, it->val)); } } return (*this);}/////这个转置的方法主要是为了保持行主排序,即使一个稀疏矩阵的元素没有按照行主的排序规则也没有关系的template<class T>void sparseMatrix<T>::transpose(void){ if() int *colSize = new int[m_col]; int *colFirst = new int[m_col]; memset(colSize, 0, m_col * sizeof(int)); memset(colFirst, 0, m_col * sizeof(int)); for (std::vector<struct element<T> >::iterator it = vec_ele.begin(); it != vec_ele.end(); it++) { colSize[it->col - 1] = colSize[it->col - 1] + 1; } colFirst[0] = 0; for (int ii = 1; ii < m_col; ii++) { colFirst[ii] = colFirst[ii - 1] + colSize[ii - 1]; } std::vector<struct element<T> > vec_res; for(std::vector<struct element<T> >::iterator it = vec_ele.begin(); it != vec_ele.end(); it++) { vec_res.insert(colFirst[it->col - 1],struct element<T>(it->col, it->row, it->val)); colFirst[it->col - 1] = colFirst[it->col - 1] + 1; } vec_ele = vec_res; vec_res.clear();}template<class T> sparseMatrix<T> sparseMatrix<T>::operator+(sparseMatrix<T>& spm){ if (m_col != spm.cols() || m_row != spm.rows()) { throw("DimensionNotMatched"); } sparseMatrix<T> spm_res(m_row, m_col); std::vector<struct element<T> >::iterator itL = vec_ele.begin(); std::vector<struct element<T> >::iterator itLEnd = vec_ele.end(); std::vector<struct element<T> >::iterator itR = spm.vec_ele.begin(); std::vector<struct element<T> >::iterator itREnd = spm.vec_ele.end(); for(; itL != itLEnd && itR != itREnd; ) { int indexL = (itL->row - 1) * m_col + itL->col - 1; int indexR = (itR->row - 1) * m_col + itR->col - 1; if(indexR == indexL) { T val = itR->val + itL->val; if (val != 0) { spm_res.vec_ele.push_back(struct element<T>(itL->row, itL->col, val)); } itL ++; itR++; } else if (indexL < indexR) { spm_res.vec_ele.push_back(struct element<T>(itL->row, itL->col, itL->val)); itL++; } else { spm_res.vec_ele.push_back(struct element<T>(itR->row, itR->col, itR->val)); itR++; } } for (; itL != itLEnd; itL++) { spm_res.vec_ele.push_back(struct element<T>(itL->row, itL->col, itL->val)); } for (; itR != itREnd; itR++) { spm_res.vec_ele.push_back(struct element<T>(itR->row, itR->col, itR->val)); } return spm_res;}template<class T>void sparseMatrix<T>::output(std::ostream& out){ out<<std::endl; for (std::vector<struct element<T> >::iterator it = vec_ele.begin(); it != vec_ele.end(); it++) { out<<"\t"<<it->row; } out<<std::endl; for (std::vector<struct element<T> >::iterator it = vec_ele.begin(); it != vec_ele.end(); it++) { out<<"\t"<<it->col; } out<<std::endl; for (std::vector<struct element<T> >::iterator it = vec_ele.begin(); it != vec_ele.end(); it++) { out<<"\t"<<it->val; } out<<std::endl;}/// 在测试重载操作符+和=的时候突然想到,是否是行主排序是很重要的。/// 如果乱序可能会导致在求和的时候导致原来的值被覆盖/// 比如一个3*3稀疏矩阵A,以行主排序的方式在向量中应该是11,13,23,33/// 和另外一个3*3的稀疏矩阵B,以行主排序的方式排列应该也是11,13,23,33/// 但是如果乱序之后,A变成11,33,13,23,B保持不变,11,13,23,33/// 那么在重载的操作符+中,被求和的顺序则变成了/// 11的两个求和,没问题,然后两个向量的迭代器都增加/// 问题出现:B的迭代器换算的索引是2,A的迭代器换算的索引是8,那么认为B在前,是单独的,/// 把B的值单独赋值进结果矩阵的13位置,然后迭代器增加,A的迭代器不改变,B指向23,换算出来的索引是5,还是比A的索引小/// 仍旧B的值单独赋值到新的矩阵的23位置,然后B的迭代器增加,A不变,B变成33,好,两个迭代器相同了/// 把计算结果赋值到33位置,这个也没有问题,然后两者的迭代器都增加,但是B到了迭代器的终点,A还在中间,/// 指向13,然后把13位置的元素和23位置的元素替换为A中对应位置的值。/// 所以,从上面的过程可以看出,一个错误的结果顺序会导致大量的元素的值为错误,/// 或者,比如原来正常13和23的对应求和均为0,现在这种错误顺序会导致结果不为0,造成稀疏矩阵的元素个数不正确template<class T>std::ostream& operator<<(std::ostream& out, sparseMatrix<T>& spm){ spm.output(out); return out;}#endif
下面的是使用的测试用例,仅仅测试了一些,没有完全测试,后面会补上。
#include <iostream>#include "mySparseMatrix.cpp"#include "myMatrix.cpp"void main(void){ sparseMatrix<int> spm1; std::cout<<spm1<<std::endl; sparseMatrix<int> spm2; std::cout<<spm2<<std::endl; sparseMatrix<int> spm3(3,3); spm3 = spm1 + spm2; std::cout<<spm3<<std::endl; std::system("pause");}
模板类的未测试函数在调用的时候还是可能连编译都通不过,这个是模板类编译的一个特点,后期需要研究。
阅读全文
0 0
- 数据结构之 矩阵---稀疏矩阵
- 数据结构之稀疏矩阵
- 数据结构之稀疏矩阵
- 经典数据结构之稀疏矩阵
- 【数据结构】稀疏矩阵,对称矩阵
- 数据结构之稀疏矩阵17简要介绍
- 数据结构之---C语言实现稀疏矩阵
- 算法与数据结构之稀疏矩阵
- 数据结构实验之数组二:稀疏矩阵
- 数据结构实验之数组二:稀疏矩阵
- 数据结构实验之数组二:稀疏矩阵
- 数据结构实验之数组二:稀疏矩阵
- 数据结构实验之数组二:稀疏矩阵
- 数据结构实验之数组二:稀疏矩阵
- 数据结构实验之数组二:稀疏矩阵
- 数据结构实验之数组二:稀疏矩阵
- 数据结构实验之数组二:稀疏矩阵
- 数据结构实验之数组二:稀疏矩阵
- Visual Studio扩展开发——菜单与工具栏中的信息共享
- 汇编-使用VS2008查看反汇编语言
- 静态导入Static import
- 函数实现乘法表,两数交换,判断闰年,初始、逆置、清空数组
- Codeforces 628D Magic Numbers 数位DP
- 数据结构之 矩阵---稀疏矩阵
- 99%的人都理解错了HTTP中GET与POST的区别
- python: int函数
- Redis五种基本数据类型
- 4.3(2)
- 原理图方式与验证
- usaco6.3.1 Fence Rails
- 前端常见跨域解决方案(全)
- java中的String类常量池详解