行主映射:将矩阵依此从每一行的索引从左至右连续编号,将二维矩阵的索引映射为一维数组。
列主映射:将矩阵依此从每一列的索引从上至下连续编号,将二维矩阵的索引映射为一维数组。
本文的多种矩阵均采用行主映射,使用一维数组来表达多种矩阵。例如按照常规对二维矩阵进行描述的C++二维数组中,矩阵元素M(3,5)对应二维数组Array[2][4]。而采用一维映射后,该元素对应一维数组的Array[3*矩阵的列+5-1]。这样映射的好处在于节省内存空间,提高一些操作(如转置,矩阵乘法)的运行效率,虽然对于一般矩阵的提升不够明显,但是对于类似一些特殊矩阵(如对角矩阵、三对角矩阵、稀疏矩阵)所带来的效果极其明显。
对于特殊矩阵,需要重新定义数据结构进行存储。常见的一种方法是用三元组表达(row,col,value),以节省空间并提高效率。同时,因为与常规矩阵结构的不同,其加减乘除等操作需要重新编写算法。
本文中会用到以前编写的自定义异常类、数组线性表等程序。见线性表–数组/vecotr描述。
一般矩阵(m*n):
实现矩阵的加/减/乘运算和矩阵类的各种拷贝控制成员以及其它一些读写操作。具体思想以及其他一些思考见注释。
#pragma once
#include <iostream>
#include <algorithm>
#include <iomanip>
#include "../../../ch06/ChainList/ChainList/illegalParameterValue.h"
using std::cin; using std::cout; using std::ends; using std::endl;
//前置声明
template <typename T> class myMatrix;
//将operator<<声明为模板 使用myMatrix的模板形参作为自己的模板实参 限定友好关系
template <typename T> std::ostream& operator<<(std::ostream& os,const myMatrix<T>& matrix);
template <typename T>
class myMatrix{
friend std::ostream& operator<<<T>(std::ostream& os,const myMatrix<T>& matrix);
public:
myMatrix()= default;
myMatrix(size_t _row,size_t _col);
myMatrix(const myMatrix<T>& rhs);//copy constructor
myMatrix(myMatrix<T>&& rhs);//move construcotr
~myMatrix() {
delete element; }
size_t get_row()const {
return row; }
size_t get_col()const {
return col; }
T& operator()(size_t _row,size_t _col) const;//重载()来表示矩阵行列的索引 并完成矩阵数学逻辑上的索引到内存数组索引的映射
void set(size_t _row,size_t _col,const T& _element);//改变矩阵(i,j)元素
void reset();//将矩阵全部元素复位为0
myMatrix<T>& tranpose();//将矩阵转置
myMatrix<T>& operator=(const myMatrix<T>& rhs);//copy assignment
myMatrix<T>& operator=(myMatrix<T>&& rhs);//move assignment
myMatrix<T> operator+(const myMatrix<T>& rhs) const;//矩阵加法
myMatrix<T> operator-(const myMatrix<T>& rhs) const;//矩阵减法
myMatrix<T> operator*(const myMatrix<T>& rhs) const;//矩阵乘法
myMatrix<T> operator+() const;//一元操作符+ 取正
myMatrix<T> operator-() const;//一元操作符- 取负
myMatrix<T>& operator+=(const myMatrix<T>& rhs);//复合赋值运算符
myMatrix<T>& operator+=(size_t _unit);//复合赋值运算符 该矩阵加上一个数_unit(即_unit个单位矩阵)
myMatrix<T>& operator-=(const myMatrix<T>& rhs);//复合赋值运算符
myMatrix<T>& operator-=(size_t _unit);//复合赋值运算符 该矩阵减去一个数_unit(即_unit个单位矩阵)
myMatrix<T>& operator*=(size_t _unit);//复合赋值运算符 该矩阵乘以一个数_unit(即_unit个单位矩阵)
private:
size_t row, col;//矩阵的行列
T* element;//数组element
void check_if_same_size(size_t rhs_col,size_t rhs_row)const;//检查2个矩阵是否行可加减(行数列数相同)
void check_if_multiplicable(size_t rhs_row) const;//检查2个矩阵是否可相乘(列数=行数)
};
template <typename T>
myMatrix<T>::myMatrix(size_t _row,size_t _col):row(_row),col(_col) {
//检验矩阵行列参数的有效性
if (row < 0 || col < 0) throw illegalParameterValue("Rows and columns must be>=0!");
//行列不能只有其中一个为0(可以同时为0 生成0*0的矩阵)
if ((row == 0 || col == 0) && (row != 0 || col != 0))
throw illegalParameterValue("Either both or neither rows and columns should be 0!");
element = new T[row*col];
}
template <typename T>
myMatrix<T>::myMatrix(const myMatrix<T>& rhs):row(rhs.row),col(rhs.col) {
//拷贝构造函数
element = new T[row*col];
//利用std::copy拷贝rhs的元素
//注意 copy(start,end,target)的拷贝范围是[start,end) 所以end要比元素个数多1
std::copy(rhs.element, rhs.element + rhs.row*rhs.col, element);
}
template <typename T>
myMatrix<T>::myMatrix(myMatrix<T>&& rhs) :row(rhs.row),col(rhs.col),element(rhs.element){
//移动构造函数
//直接接管资源 然后将rhs置于可析构状态
cout << "move constructor" << endl;
rhs.element = nullptr;
}
template <typename T>
T& myMatrix<T>::operator()(size_t _row,size_t _col) const{
//检查序列(row,col)是否合法
if (_row<1 || _col<1 || _row>row || _col>col)
throw illegalParameterValue("i or j of matrix(i,j) out of range");
return element[(_row-1)*col+(_col-1)];//数学逻辑到物理地址的映射
}
template <typename T>
void myMatrix<T>::set(size_t _row,size_t _col,const T& _element) {
operator()(_row,_col) = _element;
}
template <typename T>
void myMatrix<T>::reset() {
//将所有元素置为0
for (size_t i = 0; i < row*col; ++i)
element[i] = 0;
}
template <typename T>
void myMatrix<T>::check_if_same_size(size_t rhs_row,size_t rhs_col)const {
if (row != rhs_row || col != rhs_col)
throw illegalParameterValue("rows and columns of two matrixs must be the same!");
}
template <typename T>
void myMatrix<T>::check_if_multiplicable(size_t rhs_row)const {
if (col != rhs_row)
throw illegalParameterValue("columns of left matrix and rows of right matrix must be the same to multiply!");
}
template <typename T>
myMatrix<T>& myMatrix<T>::operator=(const myMatrix<T>& rhs) {
//拷贝赋值运算符
//先拷贝再释放内存避免自赋值
row = rhs.row;
col = rhs.col;
T* newdata = new T[row*col];
std::copy(rhs.element, rhs.element + row*col, newdata);
delete[] element;
element = newdata;
}
template <typename T>
myMatrix<T>& myMatrix<T>::operator=(myMatrix<T>&& rhs) {
//移动赋值运算符
//直接接管资源
if (this!=&rhs) {
//避免自赋值
row = rhs.row;
col = rh