程序描述

首先要求用户输入矩阵的大小n(默认不超过10),然后再提示用户输入大小为n的方阵。因为输入的方阵可能含有较多的0元素,因此用了数据结构上的矩阵的压缩方法来存储稀疏矩阵。矩阵的每一个非零元用一个结构体对象来存储,里面存储着这个非零元的值,下一个非零元的地址,此非零元所在的列y。我定义的结构体中没有存储非零元所在的行号,这是因为我用一个指针数组来指向矩阵的每一行,因此,矩阵的行号信息存储在头指针中,之所以给每一行都定义一个头指针,是因为后面还要对矩阵进行行变换,这样会方便行互换操作的进行,到时候只需交换头指针就可以实现行互换的功能。同时,我还在程序中定义了一个二维数组用来存储输入的矩阵,定义这个二维数组的目的完全是为了输出矩阵的时候方便(因为要把变换之后的矩阵输出),真正的迭代过程是用稀疏矩阵来实现的。用户输入矩阵之后,程序自动建立矩阵的链表存储,判断矩阵主对角线上是否有非零元,若有,则尝试转换(其实此转换功能没有实际用处,因为后面还要进行主对角占优的转化,如果一个矩阵是主对角占优的,那么它的主对角线一定不存在零元。),再判断是否为主对角占优,若否,则尝试转换,任一转换过程失败,则程序结束执行。若前面的转换都成功了或不需要进行转换,则要求用户输入列向量b,初始迭代值,迭代精度(用范式来确定),迭代上限。之后分别计算雅可比迭代和高斯赛德尔迭代,迭代过程相对来说比较简单,关键点是用精度来作为程序执行结束的条件。

思路讲解

将主对角线调整为不含零元的形式。
比如说下面的这个四阶矩阵:
0 1 1 0
1 0 0 1
0 1 0 1
1 1 0 0
当我们输入这个矩阵的时候,用一个二维数组做一些标记,对于此矩阵来说,二维数组mov_pos的内容为
2 3 0 0
1 4 0 0
2 4 0 0
1 2 0 0
这个二维数组存储的内容实际上每行可以移动的位置,比如说矩阵的第一行“0 * * 0”,它只能移动到第二行和第三行,因为如果它移动到第一行或者第四行,对角线一定存在0元素。现在我们得到了四组数据,也就是二维数组mov_pos的四行数据(忽略0元素),从这四组数据中,每一组数据选一个数,如果能有这么一种选法,使得选出的这四个数互不相同(注意,不要选0,因为0没有实际意义),那么这个矩阵就可以调整成主对角线不含零元素的形式。至于应该怎样选,我用的是数据结构上老鼠走迷宫的思想,先从第一组数据里选它的第一个数,选出来的是2,再从第二组数据里选第一个数,这时比较选出的数中有没有重复的,因为此时选出的数为{2,1},所以无重复,那么选第三组数据的第一个数2,此时选出的数为{2,1,2},我们发现有重复了,那么我们重新选第三行的数据,既然第三行的第一个数据不行,那么我们选第二个数据4,此时选出的数据是{2,1,4},发现无重复,那么继续进行,选第四行的第一个数1,发现有重复,重新选择第四行的第二个数据2,发现还是有重复,这时第四行的所有数据都已经被我们选了一遍了,那么这时就需要退回第三行。(其实在选数的时候,还用到了一个一位数组,这个数组标记第i行数据选到第a个数了,因此next[i]=a。)到了第三行发现此行的所有元素也都选过了,因此就退回到第二行,发现第二行的第二个元素没有选过,那么此时选择的数据列为{2,4},然后再去第三行选择数据,依次类推。
调整为主对角占优的方法。
这个相对来说简单一点,在输入矩阵的时候,就标记下每行最大元所在的位置j,之后判断能不能把此行移动第j行,然后再判断主对角线元素的绝对值是否大于此行其它元素绝对值之和就可以了。

代码实现

如果代码中bug,欢迎各位批评指正

#include "pch.h"   //非VS2017编译器把此行注释掉
#include "stdio.h"
#include "malloc.h"
#include "math.h"//比较一个数和其余的数是否相同,若相同返回flase
bool not_compare(int * array, int value, int n) {if (value == 0)return false;for (int i = 1; i < n; i++) if (value == array[i])return false;return true;
}
//求范数
double paradigm(double * x1, double * x2, int n) {double result = 0;for (int i = 1; i <= n; i++) result = result + fabs(x1[i] - x2[i]);return result;
}
struct matrix {     //压缩矩阵,用链表存储double value;    //非零元素的值int y;          //所在的列号matrix * next;
};int main() {double initial_matrix[10][10] = { 0 };   //压缩之前的矩阵int move_pos[10][10] = { 0 }; //矩阵的当前行可以移动的位置int array[10] = { 0 };  //存放排序之后每行矩阵的位置int max_position[10];    //每行最大数所在的列号int max_num;    //中间变量,记录每行的最大值double x0[10];    //雅可比迭代double x1[10];   //雅可比迭代double x[10];    //高斯赛德尔迭代结果double b[10];    //行矩阵bint n;    //矩阵的大小int count;   double precision;   //迭代精度double a[10]; //存放主对角线的元素int N;   //迭代次数的上限int flag1 = 0;    //标记主对角线存在非零元int flag2 = 0;    //调整矩阵时用到int flag3 = 0;    //记录精度是否达到要求,达标则flag3为0int flag4 = 0;   //标记是否进行了对角占优化matrix  head[10]; //每行矩阵都有一个头结点matrix * hp;printf("请输入矩阵的大小n:");scanf("%d", &n);printf("请输入%d阶矩阵\n", n);for (int i = 1; i <= n; i++) {hp = & head[i];count = 1;max_num = 0;for (int j = 1; j <= n; j++) {scanf("%lf", &initial_matrix[i][j]);if (initial_matrix[i][j] != 0) {matrix * p = (matrix *)malloc(sizeof(matrix));hp->next = p;hp = p;p->next = NULL;p->y = j;p->value = initial_matrix[i][j];move_pos[i][count++] = j;    //记录当前行可以移动到第j行上去//判断当前输入是否为本行最大值if (fabs(initial_matrix[i][j]) > max_num) {max_num = fabs(initial_matrix[i][j]);max_position[i] = j;}}}if (initial_matrix[i][i] == 0)flag1 = 1;    //标记主对角线存在非零元}//进行矩阵的变换,通过行互换实现if (flag1 == 1) {printf("此矩阵主对角线存在非0元,正在尝试转换...\n");bool cannot_dia = false;  //标记是否可以变为主对角元全非零的形式int next[10] = { 0 };  //用next[j]记录第j行比较到哪一个元素for (int i = 1; (i <= n) || (flag2 == 1); i++) {if (flag2 == 1) {i = i - 2;if (i == 0) {cannot_dia = true;break;} //ifnext[i]++;flag2 = 0; }   //iffor (int j = 1;; j++) {if (not_compare(array, move_pos[i][next[i] + 1], i)) {array[i] = move_pos[i][next[i] + 1];break;}else next[i]++;if (move_pos[i][next[i] + 1] == 0) {flag2 = 1;   //此行所有元素都与前面所选的重复,因此只能退回到前一行,重新选择next[i] = 0;break;}}    //for}  //forif (!cannot_dia) {int temp_array[10];for (int i = 1; i <= n; i++)temp_array[i] = array[i];for (int i = 1; i <= n; i++) {array[temp_array[i]] = i;}printf("变换成功,变换之后的矩阵为:\n");for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++)printf("%.0f ", initial_matrix[array[i]][j]);printf("\n");    //每输出n个元素换行}}   //if (!cannot_dia)else{printf("转换失败");return 0;} }    //if (flag1 == 1)//判断是否为对角占优for (int i = 1; i <= n; i++)for (int j = i + 1; j <= n;j++)if (max_position[i] == max_position[j]) { //移动位置发生冲突,第i行和第j行想要移动到相同的位置printf("无法使其变为对角占优矩阵\n");return 0;}for (int i = 1; i <= n; i++) {double result = 0;for (int j = 1; j <= n; j++)if (max_position[i] != j)result = result + fabs(initial_matrix[i][j]);if (result >= fabs(initial_matrix[i][max_position[i]])) {   //不满足绝对值最大的元素大于其他元素绝对值之和这一条件printf("无法使其变为对角占优矩阵\n");return 0;}}for (int i = 1; i <= n; i++) {if (max_position[i] != i) {     //绝对值最大的元素没有在主对角线上flag4 = 1;int temp_max[10];for (int i = 1; i <= n; i++)temp_max[i] = max_position[i];for (int i = 1; i <= n; i++) {max_position[temp_max[i]] = i;}printf("现在输出调整之后的对角占优矩阵\n");for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++)printf("%.0lf ", initial_matrix[max_position[i]][j]);printf("\n");}break;}//if (max_position[i] != i)}printf("请输入b\n");for(int i = 1; i <= n;i++)scanf("%lf",&b[i]);printf("请输入初始的迭代值\n");for (int i = 1; i <= n; i++) {scanf("%lf", &x0[i]);x[i] = x0[i];}printf("请输入迭代精度:");scanf("%lf", &precision);printf("请输入迭代上限:");scanf("%d", &N);if (flag4 == 1) {//对压缩矩阵进行变换↓matrix * temp[10];for (int i = 1; i <= n; i++) {temp[i] = head[i].next;   //保存每个头结点所指向的结点位置}for (int i = 1; i <= n; i++) {head[i].next = temp[max_position[i]];}//对压缩矩阵进行变换↑//对数组b进行变换,因为前面对矩阵进行了调整↓double b_temp[10];for (int i = 1; i <= n; i++) {b_temp[i] = b[i];}for (int i = 1; i <= n; i++) {b[i] = b_temp[max_position[i]];}//对数组b行变换,因为前面对矩阵进行了调整↑}//寻找主对角线的元素,并存储到数组afor (int i = 1; i <= n; i++) {hp = head[i].next;while (hp) {if (hp->y == i) {a[i] = hp->value;break;}hp = hp->next;}}//雅可比迭代for (int j = 1; j <= N; j++) {for (int i = 1; i <= n; i++) {hp = head[i].next;double sum = 0;        //xj * aij的累加和 while (hp) {if (hp->y == i) {hp = hp->next;continue;}sum = sum + hp->value * x0[hp->y];hp = hp->next;}x1[i] = 1.0 / a[i] * (b[i] - sum);}if(paradigm(x1, x0, n) < precision) {printf("\n");printf("雅可比迭代次数为%d次\n",j);printf("迭代结果为:\n");for (int i = 1; i <= n; i++) {printf("%f ", x1[i]);}printf("\n");break;}else for (int i = 1; i <= n; i++) {x0[i] = x1[i];}if (j == N)printf("雅可比迭代已达到迭代上限,迭代失败。\n");}//高斯赛德尔迭代for (int j = 1; j <= N; j++) {for (int i = 1; i <= n; i++) {hp = head[i].next;double sum = 0;while (hp) {if (hp->y == i) {hp = hp->next;continue;}sum = sum + hp->value * x[hp->y];hp = hp->next;}if (fabs(1.0 / a[i] * (b[i] - sum) - x[i]) > precision)flag3 = 1;x[i] = 1.0 / a[i] * (b[i] - sum);}if (flag3 == 0) {printf("\n");printf("高斯赛德尔迭代次数为%d次\n",j);printf("迭代结果为:\n");for (int i = 1; i <= n; i++) printf("%f ", x[i]);printf("\n");break;}else {flag3 = 0;}if (j == N)printf("高斯赛德尔迭代已达到迭代上限,迭代失败。\n");}}

运用雅可比和高斯赛德尔迭代公式求解方程组,并尝试将矩阵变为主对角占优矩阵相关推荐

  1. 运用雅可比(Jacobi)和高斯-赛德尔(GS公式)求解方程组

    实验名称: 运用雅克比和高斯赛德尔公式求解方程组 实验目的: a. 比较两种方法的收敛速度 b. 验证收敛条件的正确性 实验内容 1.比较两种方法的收敛速度 Jacobi公式原理 xi(k+1)=1a ...

  2. matlab用雅可比(Jacobi)迭代法求解方程组

    function x=myjacob(A,b,x0) myeps=0.0001; n=length(b); err0=1; while err0>myepsx1=zeros(n,1);for i ...

  3. matlab用雅可比迭代法,如何利用MATLAB求解线型方程组--雅可比迭代法、高斯赛德尔迭代法...

    文章目录 前言 1 直接法 2 迭代法 小结 前言 今天我们要说的就是数值微积分,赶紧看看他和高等数学中的微积分有什么区别吧.本文是科学计算与MATLAB语言专题六第2小节的学习笔记,如果大家有时间的 ...

  4. 高斯赛尔德c语言算法,高斯-赛德尔迭代法的算法及程序设计.doc

    PAGE 题 目:高斯-赛德尔迭代法的算法及程序设计 摘要 本文通过理论与实例对线性方程组的解法.收敛性及误差分析进行了探讨.在对线性方程组数值解法的讨论下用到了高斯-赛德尔迭代法,进一步研究和总结了 ...

  5. 高斯赛德尔迭代c语言_逐次超松弛SOR迭代概述

    本文使用 Zhihu On VSCode 创作并发布 逐次超松弛(SOR)迭代法概述 一.方法背景 ​ 逐次超松弛迭代法是高斯-塞德尔迭代法的一种变种,是为了解决线性方程组的一种迭代方法.由David ...

  6. 雅可比迭代和高斯—赛德尔迭代法

    一.雅可比迭代法 对于线性方程组AX=b,我们首先将系数矩阵A分解为对角矩阵D.下三角矩阵L和上三角矩阵U: 1.1雅可比迭代法的matlab代码 在这里,我们求解下面的带状方程(以下程序均是以求解该 ...

  7. Python——高斯赛德尔迭代求线性方程组的根

    高斯赛德尔迭代 与雅克比迭代对比:Python--雅克比迭代求线性方程组的根 计算代码 矩阵A--方程组的系数.代码中只需改变矩阵系数即可 矩阵B--方程组等号右侧的常数. #高斯赛德尔迭代 #求解方 ...

  8. Matlab实现——严格对角占优三对角方程组求解(高斯赛尔德Gauss-Seidel迭代、超松弛)

    欢迎前往个人博客 驽马点滴 和视频空间 哔哩哔哩-<挨踢日志> 严格对角占优三对角方程组求解 对中等规模的n阶的(n<100)线性方程组,直接法的准确性和可靠性,所以常采用直接法 对 ...

  9. matlab trisys,Matlab实现——严格对角占优三对角方程组求解(高斯赛尔德Gauss-Seidel迭代、超松弛) | 学步园...

    严格对角占优三对角方程组求解 对中等规模的n阶的(n<100)线性方程组,直接法的准确性和可靠性,所以常采用直接法 对于较高阶的方程组,特别是地于某些偏微分方程离散化后得到的大型稀疏方程组(系统 ...

最新文章

  1. 理想汽车事故,智能短板暴露
  2. git在提交的时候报错:Your branch is up to date with ‘origin/master‘
  3. JavaScript -- 时光流逝(三):js中的 String 对象的方法
  4. java 查询线程池_[代码全屏查看]-我的 Java 线程池测试类
  5. mongodb java spring_[Java教程]Spring 与 mongoDB 整合
  6. 华为手机截屏怎么截长图_华为手机5种常用截屏方式,教你轻松定格屏幕精彩瞬间...
  7. 今日头条挖角微信;中国 iPhone 购买意创新低;小程序将分级 | 极客头条
  8. 学会了selenium 模拟鼠标操作,你就可以偷懒点点点了
  9. Bailian2701 Bailian3864 POJ NOI0105-39 与7无关的数【进制】
  10. dynamic结合匿名类型 匿名对象传参
  11. 同一页面中加载两个相同的控件,结果只能出来一个,这是为什么
  12. Hyperledger Fabric 或 Composer 获取指定区块的信息
  13. 赛车游戏代码大全html,赛车游戏代码
  14. 最大流问题之FF算法与EK算法
  15. Leetcode-845. 数组中的最长山脉(最详细解法)
  16. mp4转换m3u8格式php,m3u8格式怎么转换mp4 ts格式转换 - 下载的m3u8、ts如何转换成mp4...
  17. 安庆集团-冲刺日志(第六天)
  18. CentOS7查看和关闭防火墙
  19. 推荐几个中文在线音乐网站
  20. 你知道一本书封面的著、编著、编、主编分别是什么意思吗?

热门文章

  1. 微米纳米机器人 课件_纳米技术课件演示.ppt
  2. PHP 获取用户客户端IP的解决方案
  3. 分享两个Latex在线公式编辑器的网站
  4. 我的第一次Linux博客
  5. 【蓝桥杯-单片机学习笔记(十七)】24C02原理及其读写操作
  6. CodeLite 5.1 发布,C++ 集成开发环境
  7. Project ‘cv_bridge‘ specifies ‘usr/include/opencv‘ as an include dir, which is not found.
  8. 微信小程序挂号预约系统+后台管理系统
  9. ELINK编程器典型场景之多APP文件下载
  10. android 苹果 蓝牙版本怎么升级,Android平台AIDA64更新至1.53版新增实用功能,可查看蓝牙版本...