C++矩阵类使用一维数组存储数据,并使用QR分解求解特征值,特征向量,并用注释写出怎么一步步实现
时间: 2024-03-25 15:36:16 浏览: 103
以下是使用一维数组存储数据并使用QR分解求解特征值和特征向量的C++矩阵类的实现,同时附有注释说明:
```c++
#include <iostream>
#include <cmath>
using namespace std;
const double EPS = 1e-10; // EPS为极小值,用于判断浮点数是否为0
class Matrix {
public:
Matrix(int r, int c) : rows(r), cols(c) {
data = new double[rows * cols]; // 动态分配内存
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
data[i * cols + j] = 0; // 初始化为0
}
~Matrix() { delete[] data; } // 释放内存
double& operator()(int i, int j) { return data[i * cols + j]; } // 矩阵元素的访问
void print() { // 输出矩阵
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++)
cout << (*this)(i, j) << " ";
cout << endl;
}
}
void QR(Matrix& Q, Matrix& R) { // QR分解
double* u = new double[rows]; // 临时向量u
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++)
u[j] = (*this)(j, i); // 取出第i列,作为u向量
for (int j = 0; j < i; j++) {
double dot = 0;
for (int k = 0; k < rows; k++)
dot += u[k] * R(k, j); // 计算u向量和R矩阵的第j列的点积
for (int k = 0; k < rows; k++)
u[k] -= dot * R(k, j); // u向量减去投影
}
double norm = 0;
for (int j = 0; j < rows; j++)
norm += u[j] * u[j]; // 计算u向量的模长
norm = sqrt(norm);
if (norm < EPS) // 如果模长为0,跳过该列
continue;
for (int j = 0; j < rows; j++)
u[j] /= norm; // 归一化
for (int j = 0; j < rows; j++)
Q(j, i) = u[j]; // 将u向量作为Q矩阵的第i列
for (int j = i; j < cols; j++) {
double dot = 0;
for (int k = 0; k < rows; k++)
dot += u[k] * (*this)(k, j); // 计算u向量和A矩阵的第j列的点积
R(i, j) = dot; // 记录投影
}
}
delete[] u; // 释放内存
}
void eigen(Matrix& eigenvectors, Matrix& eigenvalues) { // 求特征值和特征向量
Matrix Q(rows, cols);
Matrix R(cols, cols);
Q.setIdentity(); // 初始化Q矩阵为单位矩阵
R.fill(0); // 初始化R矩阵为0
for (int i = 0; i < 10; i++) { // 最多迭代10次
QR(Q, R); // 进行QR分解
*this = R * Q; // 计算A矩阵的下一次迭代
}
eigenvalues.resize(cols, 1); // 初始化特征值矩阵
eigenvectors.resize(rows, cols); // 初始化特征向量矩阵
for (int i = 0; i < cols; i++) {
eigenvalues(i, 0) = (*this)(i, i); // 将A矩阵的对角线元素作为特征值
for (int j = 0; j < rows; j++)
eigenvectors(j, i) = Q(j, i); // Q矩阵的第i列作为特征向量
}
}
void setIdentity() { // 初始化为单位矩阵
fill(0);
for (int i = 0; i < rows && i < cols; i++)
(*this)(i, i) = 1;
}
void fill(double val) { // 填充矩阵
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
(*this)(i, j) = val;
}
void resize(int r, int c) { // 重新设置行数、列数
double* newdata = new double[r * c];
for (int i = 0; i < r; i++)
for (int j = 0; j < c; j++)
newdata[i * c + j] = (i < rows && j < cols) ? data[i * cols + j] : 0;
delete[] data;
data = newdata;
rows = r;
cols = c;
}
private:
int rows, cols;
double* data;
};
int main() {
Matrix A(3, 3); // 创建一个3x3的矩阵A
A(0, 0) = 1; A(0, 1) = 2; A(0, 2) = 3;
A(1, 0) = 2; A(1, 1) = 3; A(1, 2) = 2;
A(2, 0) = 3; A(2, 1) = 2; A(2, 2) = 1;
Matrix eigenvectors, eigenvalues;
A.eigen(eigenvectors, eigenvalues); // 求解特征值和特征向量
cout << "Eigenvalues:" << endl;
eigenvalues.print(); // 输出特征值
cout << "Eigenvectors:" << endl;
eigenvectors.print(); // 输出特征向量
return 0;
}
```
注释中解释了每个函数的功能和实现方法,其中最重要的是QR分解的实现,通过QR分解可以将矩阵分解为一个正交矩阵Q和一个上三角矩阵R的乘积,从而求解矩阵的特征值和特征向量。在实现中,我们使用一维数组存储矩阵数据,通过重载()运算符实现矩阵元素的访问。
阅读全文