幂法的主要作用是求矩阵的主特征值,这种方法特别适用于求大型稀疏矩阵。
设A∈有n个线性无关的特征向量,主特征值满足>·····,则对任意非零初始向量(0),按照下述方法构造的向量序列{},{}:
(P.S)过程迭代讲解:
第一步:定义一个初始规范化向量。
第二步:初始规范化向量与矩阵A相乘得到一个结果矩阵
第三步:取结果矩阵的最大值,即({})
第四步:将初始规范化向量除以矩阵的最大值得到下一次迭代所需的规范化向量。
第五步:用新得到的规范化向量重复以上四个步骤。
注释:
当迭代次数k趋于无穷时, 结果矩阵的最大值,即({})为主特征值。
当迭代次数k趋于无穷时,规范化向量即为主特征值对应的特征向量(这个特征向量是除以了最大值后所得的)
主要分为三个模块:赋值、求解函数、输出;
在这里主要讲解求解函数和输出模块。
主要有四个循环语句,和两个调用函数组成。
1.执行第一个循环,主要计算两个矩阵某行列相乘
2.执行第二个循环,主要用于计算两矩阵相乘后得到的新矩阵
3.执行第三个循环,主要用于上一次迭代后得到的规范化向量与矩阵相乘
4.一个插入循环,该循环位于第二个循环与第三个循环之间,主要担任桥梁角色,将每次相乘得到的矩阵赋值给一个临时数组,该数组主要是用于取最大值函数。
调用函数:
一个取最大值函数,一个求规范化向量函数
这两个调用函数紧接着上述的插入循环,主要是由于插入循环提供了一个可以求该次两矩阵相乘后得到临时数组,该数组可以求出最大值,之后可以为求规范化向量提供最大值。该最大值将被一个以迭代次数为坐标的一个定义变量(M_v[k])储存起来,这样就可以构建出迭代次数与最大值一一对应的关系,便于后续的结果输出。
该模块最关键点是将迭代次数、规范化向量以及最大值统一起来。
在该模块中,我通过以迭代次数为坐标,建立每次迭代规范化向量和最大值的存储数组,这样的好处是在以迭代次数递增的循环语句中,每执行一次循环就可以输出该次的迭代次数、规范化向量和最大值。
(p.s)以上都是自己的个人理解,讲解的不是很专业。
#include <iostream> #include <iomanip>//用于cout保留小数 double a[100][100];//定义A矩阵 double u[100][100];//定义规范化向量U double v[100][100];//定义Au的结果结果矩阵 double max_v;//定义Au的结果矩阵的最大值 double M_v[100]; //定义Au的结果矩阵的最大值,为了之后在循环外输出 double X_x[100];//定义赋值每次迭代Au结果矩阵 int In;//定义该次的迭代次数(p.s便于在求解循环调用函数中赋值下次迭代所需的规范化向量U) int I[100];//定义现已迭代的次数(P.S便于后续的输出,使迭代次数与迭代结果一一对应 double max(double X_x[],int n);//定义取最大值函数 void dev_u(double X_x[], int n);//定义Au结果矩阵每个元素除以元素最大值的函数 using namespace std; int main() { int n; cout << "请输入A矩阵的阶数n" << endl; cin >> n; int N; cout << "请输入迭代次数N" << endl; cin >> N; cout << "************请输入A矩阵的各个元素************" << endl; cout << endl; for (int i = 1; i <= n; i++) { cout << "请输入第" << i << "行的元素" << endl; for (int j = 1; j <= n; j++) { cin >> a[i][j]; } } cout << "请输初始规范化向量" << endl; for (int i = 1; i <= n; i++) { cin >> u[1][i]; }//赋值模块 for (int k = 1; k <= N; k++)//执行第三个循环,主要用于上一次迭代后得到的规范化向量与矩阵相乘 { I[k] = k; In = k; for (int i = 1; i <= n; i++)//执行第二个循环,主要用于计算两矩阵相乘后得到的新矩阵 { for (int j = 1; j <= n; j++)//执行第一个循环,主要计算两个矩阵某行列相乘 { v[k][i] += a[i][j] * u[k][j]; } } for (int p = 1; p <= n; p++)//该循环赋值主要担任桥梁角色,将每次相乘得到的矩阵赋值给临时数组,该数组主要是用于取最大值函数中; { X_x[p] = v[k][p]; }// max(X_x, n);//调用取最大值函数 dev_u(X_x, n);//调用求规范化向量函数 M_v[k] = max_v;//将每次得出的最大值储存起来,便于后续的输出 }//特征值函数求解模块 cout << "****************输出计算结果****************" << endl; cout << endl; cout << setiosflags(ios::fixed) << setprecision(8);//输出结果保留8位小数 cout << "迭代次数" << " max{vk} " << " 规范化向量uk^(T) " << endl; for (int i = 1; i <= N; i++) { cout <<" 第" << I[i] <<"次" << " " << M_v[i] << " "; for (int p = 1; p <= n - 1; p++) { cout << u[i + 1][p] << " , "; } cout << u[i + 1][n] << endl; }//求解结果输出模块 cout << endl; cout <<"输出最大迭代次数后得到的主特征值以及相应的特征向量" << endl; cout << "主特征值: " << M_v[N] << " 相应的特征向量: "; for (int p = 1; p <= n - 1; p++) { cout << u[N + 1][p] << " , "; } cout << u[N + 1][n] << endl; return 0; } double max(double X_x[], int n) { max_v = X_x[1]; for (int p = 2; p <= n; p++) { if (X_x[p] > max_v) { max_v = X_x[p]; } } return max_v; } void dev_u(double X_x[], int n) { for (int p = 1; p <= n; p++) { u[In+1][p]= X_x[p] / max_v; } }
用幂法求解A矩阵的主特征值以及相应的特征向量,该例题出现在数值分析第5版,由李庆杨等人编著:
输出结果截图
现在主要在阅读学习《C++ primer Plus》,这是我接触C++的第一本书。由于课程学习要接触《数值分析》这门课,就把书上的迭代方式给程序化,就可以把学到的知识很好的结合在一起。该程序是到目前为止使用过for循环最多的。但是当弄清楚了循环关系之间的先后关系之后,就会对其由清晰的认识吧,至少我是这样的。程序化之后,能带来简便就足够了。到目前为止所做的程序都没有考虑过资源占用问题以及优化问题,只是单纯的实现罢了,写的文章都是以我这接触程序语言不久的小白的角度叙述,专业性不是很高,不过对于小白来说还是挺友好的。