0%

矩阵类

趁着线性代数的知识还热乎,简短的写了个矩阵类的demo,目前实现了

  • 矩阵的构造
  • 矩阵的运算(+ - * =)
  • 矩阵的读写

需不断更新…(对角矩阵、求矩阵的逆、伴随矩阵、对称矩阵、特征值与特征向量、矩阵相似判断、是否可对角化、二次型等实际需要时再继续学习)

矩阵类

该矩阵类包含三个私有变量,用二维容器存储矩阵中的元素值,用两个整型变量存储矩阵的行数和列数。参数的获取通过特定的函数返回,类外不能直接访问。

目前该类实现了矩阵的加减法及乘法的功能,矩阵的打印与写入文件操作。其他功能以后慢慢更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
template<class T>
class Matrix {
public:
//构造函数
Matrix(int row, int line);
Matrix(const Matrix& m);
Matrix(int row, int line, const vector<T> nums);
//矩阵参数的获取
int getRow() const{ return m_row; }
int getLine()const { return m_line; }
T getValue(int i, int j) const{ return mat[i][j]; }
//矩阵的输出
void MatPrint();
void MatWrite(string file_name);
//矩阵的读入
//void MatRead(string file_name);
//矩阵运算
Matrix operator+(const Matrix& p);
Matrix operator*(const Matrix& p);
private:
vector< vector<T> > mat;//矩阵的存储
int m_row;//行数
int m_line;//列数
};

构造函数

构造函数有三种形式,两个普通构造函数和一个拷贝构造函数

普通构造函数必须提供待构造矩阵的行列数,矩阵元素的值可通过vector容器传入

若不传入矩阵元素值,则默认为0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template<class T>
Matrix<T>::Matrix(int row, int line) {
mat.resize(row, vector<T>(line, 0));
m_row = row;
m_line = line;
}
template<class T>
Matrix<T>::Matrix(int row, int line, const vector<T> nums) {
mat.resize(row, vector<T>(line, 0));
if (nums.size() != (row * line))
cerr << endl << "数据格式与矩阵元素个数不匹配!" << endl;
int cur = 0;
for (int i = 0;i < row;i++)
for (int j = 0;j < line;j++)
mat[i][j] = nums[cur++];
m_row = row;
m_line = line;
}

拷贝构造函数需传入矩阵类型参数

1
2
3
4
5
6
template<class T>
Matrix<T>::Matrix(const Matrix& m) {
mat = m.mat;
m_line = m.m_line;
m_row = m.m_row;
}

矩阵的输入输出

矩阵的打印

1
2
3
4
5
6
7
8
9
10
11
12
template<class T>
void Matrix<T>::MatPrint() {
cout << "{" << endl;
for (int i = 0;i<m_row;i++) {
cout << "[";
for (int j = 0;j < m_line-1;j++)
cout << mat[i][j] << ",";
cout << mat[i][m_line - 1];
cout << "]" << endl;
}
cout << "}" << endl;
}

矩阵的文件写入操作

文件的写采用附加写的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template<class T>
void Matrix<T>::MatWrite(string file_name) {
ofstream fout;
fout.open(file_name,ios::app);
if (!fout.is_open())
cerr << endl<< "文件打开失败!" << endl;
for (int i = 0;i < m_row;i++) {
fout << "[ ";
for (int j = 0;j < m_line - 1;j++)
fout << mat[i][j] << ",";
fout << mat[i][m_line - 1];
fout << " ]" << endl;
}
fout.close();
}

矩阵的运算

±运算符的重载

矩阵的加减运算符的重载类似。

第一步首先要判断两个矩阵的维度是否一致,在一致的前提下才能进行加减法。

  • 加法
1
2
3
4
5
6
7
8
9
10
11
12
template<class T>
Matrix<T> Matrix<T>::operator+(const Matrix<T>& matrix) {
if (this->m_line != matrix.getLine() || this->m_row != matrix.getRow()) {
cerr << endl << "无法相加!" << endl;
return Matrix(0,0);
}
Matrix tmp(this->m_row, this->m_line);
for (int i = 0;i < this->m_row;i++)
for (int j = 0;j < this->m_line;j++)
tmp.mat[i][j] = this->mat[i][j] + matrix.mat[i][j];
return tmp;
};
  • 减法
1
2
3
4
5
6
7
8
9
10
11
12
template<class T>
Matrix<T> Matrix<T>::operator-(const Matrix<T>& matrix) {
if (this->m_line != matrix.getLine() || this->m_row != matrix.getRow()) {
cerr << endl << "无法相减!" << endl;
return Matrix(0, 0);
}
Matrix tmp(this->m_row, this->m_line);
for (int i = 0;i < this->m_row;i++)
for (int j = 0;j < this->m_line;j++)
tmp.mat[i][j] = this->mat[i][j] - matrix.mat[i][j];
return tmp;
};

*运算符的重载

矩阵的乘法规则不再详述。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template<class T>
Matrix<T> Matrix<T>::operator*(const Matrix<T>& matrix) {
int row = this->m_row;
int line = matrix.m_line;
if (this->m_line != matrix.m_row){
cerr << endl << "无法相乘!" << endl;
return Matrix(0, 0);
}
Matrix tmp(row,line);
for (int i = 0;i < this->m_row;i++)
for (int j = 0;j < line;j++)
for (int k = 0;k < line;k++)
tmp.mat[i][j] += this->mat[i][k] * matrix.mat[k][j];
return tmp;
};

=运算符的重载

如果要实现类似a=b=c这种连等形式的表达式时,重载的赋值运算符的返回值可以用引用形式。

1
2
3
4
5
6
7
8
9
10
11
int temp;
int fun1()
{
temp = 10;
return temp;
}
int& fun2()
{
temp = 10;
return temp;
}

返回引用实际返回的是一个指向返回值的隐式指针,在内存中不会产生副本,是直接将temp拷贝给a,这样就避免产生临时变量,相比返回普通类型的执行效率更高,而且这个返回引用的函数也可以作为赋值运算符的左操作数。

下述代码为矩阵的赋值运算符的重载函数

1
2
3
4
5
6
7
template<class T>
Matrix<T>& Matrix<T>::operator=(const Matrix<T>& m) {
mat = m.mat;
m_line = m.m_line;
m_row = m.m_row;
return *this;
};