程序猿成长之路之番外篇——矩阵算法

今天在复习线性代数知识的过程中,用java语言简单实现了一下矩阵算法。

数学知识回顾

1.什么是矩阵
在数学领域,矩阵就像一个表格,将数据排放进去,形成一个矩形。我们习惯用一个大括号把矩阵内的数据包括进来。

1.矩阵
在数学领域,矩阵就像一个表格,将数据排放进去,形成一个矩形。我们习惯用一个大括号把矩阵内的数据包括进来。

2. 矩阵的运算
矩阵可以进行加法、乘法运算,如果是个方形矩阵也可以转置或者求逆。此外,加法和乘法都有结合律、分配律等定律。

矩阵加法运算:
在这里插入图片描述
矩阵乘法运算:
运算规则相对较为繁琐:

  1. A(m,n) * B(n,k) = C(m,k) // 具有m行n列的矩阵A 乘以具有n行k列的矩阵B结果为m行k列的矩阵c
  2. 运算过程如下图:就拿C(1,1) – 结果矩阵的第一行第一列的元素来说,它等于A(1,1) * B(1,1) + A(1,2) * B(2,1) = 1 * 2 + 2 * 6 = 14
    在这里插入图片描述
  3. 矩阵的转置
    在这里插入图片描述
  4. 矩阵求逆
    我们知道伴随矩阵 = Det(矩阵A) * 矩阵的逆
    我们又知道 伴随矩阵 = Σ(Aij 的代数余子式), i,j∈(0,size))
    因此可以求出矩阵的逆 = |伴随矩阵| / Det(矩阵A)
    求逆的难点在于获取代数余子式。

算法实现

  1. 编写matrix类
package matrixUtils;

import java.util.Arrays;

class Matrix {
	@Override
	public String toString() {
		String str = "";
		for (int i = 0; i < arr.length;i++) {
			str += Arrays.toString(arr[i]);
			str +="\n";
		}
		return str;
	}
	//宽度
	private final int width;
	//高度
	private final int height;
	//数组
	private final double[][] arr;
	
	Matrix(int width, int height) {
		this.width = width;
		this.height = height;
		arr = new double[height][width];
	}
	
	Matrix(int width, int height, double[][] arr) {
		this.width = width;
		this.height = height;
		this.arr = arr;
	}
	
	public int getWidth() {
		return width;
	}
	public int getHeight() {
		return height;
	}
	public double[][] getArr() {
		return arr;
	}
	public void setArrVal(int x, int y, double val) {
		arr[x][y] = val;
	}
	public boolean compareTo(Matrix matrix) {
		//比较
		return this.width == matrix.width 
				& this.height == matrix.height;
	}
	public void setArrVals(int startIndex, int[][] val) {
		int size = val[0].length;
		size *= val.length;
		if (startIndex < 0 || size <= 0){
			return;
		}
		//count计数器
		for (int i = 0; i < size;i++) {
			arr[i / val[0].length][i % val[0].length] = val[i/val[0].length][i % val[0].length];
		}
	}
	
}
  1. 编写工厂类
public class MatrixFactory {
	private static final int MAX_SIZE = 1 << 30;
	/**
	 * 获取实例
	 */
	public static Matrix getInstance(int width, int height) {
		if (width < 0 || width > MAX_SIZE) {
			throw new IllegalArgumentException("宽度有误");
		}
		if (height < 0 || height > MAX_SIZE) {
			throw new IllegalArgumentException("高度有误");
		}
		return new Matrix(width, height);
	}
	
	public static Matrix getInstance(int width, int height, double[][] arr) {
		if (width < 0 || width > MAX_SIZE) {
			throw new IllegalArgumentException("宽度有误");
		}
		if (height < 0 || height > MAX_SIZE) {
			throw new IllegalArgumentException("高度有误");
		}
		return new Matrix(width, height, arr);
	}
}
  1. 矩阵乘法
    设计思路:设置一个计数器m,用于获取结果的列值,当m == matrix2的宽度时,也就是说当前已经完成对i行的处理,结果保存进matrix中,让i(行数)加1并且m重置为0,否则让结果列数自加。
	/**
	 * 矩阵相乘
	 * @param matrix
	 * @return
	 */
	public static Matrix multiply(Matrix matrix1,Matrix matrix2) {
		//生成一个新的矩阵
		if (matrix1 == null || matrix2 == null) {
			throw new IllegalArgumentException("矩阵不匹配,请检查");
		}
		if (matrix1.getWidth() != matrix2.getHeight()) {
			throw new IllegalArgumentException("矩阵不匹配,请检查");
		}
		//新建一个矩阵
		Matrix resMatrix = MatrixFactory.getInstance(
				matrix2.getWidth(),matrix1.getHeight()
		);
		int m = 0; //m - matrix2的列数
		for (int i = 0; i < matrix1.getHeight();) {
			int sum = 0; //sum - 求和
			for(int j = 0; j < matrix1.getWidth(); j++) {
				/**
				 * 按照matrix1 第i行 * matrix2 第m列 得到结果保存
				 */
				sum += matrix1.getArr()[i][j] * matrix2.getArr()[j][m];
			}
			resMatrix.setArrVal(i, m, sum);
			if (m == matrix2.getWidth() - 1) {
				i++;
				m=0;
			} else {
				m++;
			}
		}
		return resMatrix;
	}
  1. 矩阵转置
    设计思路: arr[i][j] == arr[j][i]。(i,j位置上的数据互换)
/**
	 * 矩阵反转
	 * @param matrix
	 * @return
	 */
	public static Matrix reverse(Matrix matrix) {
		//生成一个新的矩阵
		if (matrix == null) {
			throw new IllegalArgumentException("矩阵不匹配,请检查");
		}
		//生成一个新的矩阵
		Matrix resMatrix = MatrixFactory.getInstance(
				matrix.getHeight(), matrix.getWidth()
		);
		for(int i =0; i <matrix.getHeight();i++) {
			for (int j = 0; j < matrix.getWidth(); j++) {
				//如果行列值一样就跳过
				if (i == j) {
					resMatrix.setArrVal(i, j, matrix.getArr()[i][j]);
					continue;
				}
				resMatrix.setArrVal(j, i, matrix.getArr()[i][j]);
			}
		}
		return resMatrix;
	}
  1. 矩阵求det
    设计思路:利用递归,每次的余子式size-1,到了size为2时就直接使用余子式公式进行计算。
/**
	 * 获取矩阵det
	 * @param matrix
	 * @return
	 */
	public static double getMatrixDet(Matrix matrix) {
		if (matrix == null) {
			throw new IllegalArgumentException("矩阵不匹配,请检查");	
		}
		int height = matrix.getHeight();
		int width = matrix.getWidth();
		if (height != width) {
			throw new IllegalArgumentException("矩阵不匹配,请检查");	
		}
		return getMatrixDet(matrix,width);
	}
	
	/**
	 * 获取矩阵det
	 * @param matrix
	 * @param width
	 * @return
	 */
	private static double getMatrixDet(Matrix matrix, int size) {
		if (size <= 1) {
			return matrix.getArr()[0][0];
		} else if (size == 2) {
			return matrix.getArr()[0][0] * matrix.getArr()[1][1] - 
					matrix.getArr()[0][1] * matrix.getArr()[1][0];
 		}
		// 计算det,每次分解成大小为size-1的数组
		int det = 0;
		
		double[][] arr = matrix.getArr();
		for(int i = 0; i < arr[0].length; i++) {
			//获取余子式
			Matrix temp = getSubMatrix(0,i,size-1,arr);
			//统计det的值
			det += (Math.pow(-1, i)) * arr[0][i] * getMatrixDet(temp,size-1);
		}
		return det;
	}
	/**
	 * 获取余子式
	 * @param x - 要去除的第几行
	 * @param y - 要去除的第几列
	 * @param size 余子式size
	 * @param arr 原数组
	 * @return
	 */
	private static Matrix getSubMatrix(int x, int y,int size,double[][] arr) {
		//每次进行temp数组的填充
		Matrix temp = new Matrix(size,size);
		int addRow = 0; //填充计数
		for (int j = 0; j <= size; j++) {
			int addColumn = 0; //填充计数
			//跳过当前一行
			if (j == x) {
				addRow++;
				continue;
			}
			for (int m = 0; m < size + addColumn; m++) {
				//i列删除
				if (m == y) {
					addColumn++;
					continue;
				}
				//从第一行开始算,自动跳过第y列的数据
				temp.setArrVal(j-addRow,m - addColumn,arr[j][m]);
			}
		}
		return temp;
	}
  1. 矩阵求逆
    设计思路:利用公式 伴随矩阵 = det(矩阵) * 矩阵进行求解

	/**
	 * 求逆矩阵
	 * @param matrix
	 * @return
	 */
	public static Matrix inverse(Matrix matrix) {
		if (matrix.getWidth() != matrix.getHeight()) {
			throw new IllegalArgumentException("矩阵不匹配,请检查");
		}
		/**
		 * AX = B
		 * A-1AX=A-1A
		 * X=A-1B
		 */
		int size = matrix.getHeight(); //size
		double[][] arr = matrix.getArr(); //arr
		//结果矩阵
		Matrix resMatrix = MatrixFactory.getInstance(size,size);
		double det = getMatrixDet(matrix); //计算det
		for (int i = 0; i < Math.pow(size,2); i++) { //size * size = length
			//获取每一项的余子式
			Matrix temp = getSubMatrix(i/size, i%size, size-1, arr);
			resMatrix.setArrVal(i/size, i%size, Math.pow(-1, i) 
					* getMatrixDet(temp) / (det * 1.0)); //计算余子式的det / 总det
		}
		return reverse(resMatrix); //转置
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/475126.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

对JS文件进行压缩未通过,对WXML文件进行压缩未通过 问题解决

问题描述 在使用uniapp 开发微信小程序&#xff0c;进行上架发布时 代码质量栏 出现对JS文件进行压缩未通过&#xff0c;对WXML文件进行压缩未通过 问题。 虽然现实代码上传成功&#xff0c;但是作为一个合格的猿人&#xff0c;肯定是要解决的。那么如何解决呢&#xff1f; …

气压传感器BMP180的简单应用

文章目录 一、BMP1801.介绍2.主要特点&#xff1a;3. 典型应用&#xff1a;4. 原理图5. 典型应用电路6. 测量流程7. 工作模式 二、软件1.初始化2.获取原始温度3.获取真实温度4.获取原始气压5.获取真实气压6.海拔高度的换算 三、总结 一、BMP180 1.介绍 BMP180是一款高精度、小…

int数组最大能设置为多长?以及能存储的数字为多大?

在编译器里&#xff0c;每种类型的变量定义数组的时候都有一个数组大小&#xff0c;而这个大小对于不同的变量而言有不同的上限&#xff0c;这里的最大长度更准确的来说应该是系统堆的最大值。 一个字符占1byte大小&#xff0c;8位&#xff0c;所以&#xff0c;理论上&#xff…

【小白入门篇2】总有一款AI工具适合你

上一篇《【小白入门篇1】GPT到底是怎样练成&#xff1f;》介绍了GPT的形成&#xff0c;直到今日&#xff0c;GPT工具层出不穷&#xff0c;搞得很多初学者眼花缭乱&#xff0c;今天梳理一下国内外比较出名的GPT工具&#xff0c;适用各个领域非专业的同学选择。GPT工具目前基本以…

安捷伦Agilent DSA91304A高性能示波器

181/2461/8938产品概述&#xff1a; DSA91304A示波器&#xff1a;13GHz 带宽。Keysight Infiniium 90000 系列示波器具有业界较低的本底噪声&#xff0c;能够提供现有示波器中更高的实时抖动测量精度。 DSA91304A Infiniium 高性能示波器&#xff1a;13 GHz Keysight Infini…

docker一键部署若依前后端分离版本

比如这里把文件放到/xin/docker/jiaoZ/的目录下&#xff0c;jar包和下面的配置文件都放在这个文件夹下。 注意要把jar端口改为你实际启动的&#xff0c;映射端口也可以改为你想要的。 这里的映射端口为&#xff1a;nginx监听80端口&#xff0c;jar在8620端口&#xff0c;mysq…

Python分析人民日报关于台湾的报道

【项目背景】 《人民日报》数据挖掘&#xff0c;时间&#xff1a;1949.10.1-2023.12.31 标题含有“台湾”的报道 需要以下内容 1、标题&#xff0c;即上述时间段的报道标题和相应的报道时间、版面 2、包含标题、时间、版面的所有报道内容 3、报道的年份和数量的趋势图 4、…

new mars3d.layer.BusineDataLayer({加载动态的.png图标

问题&#xff1a; 用BillboardEntity或者BusineDataLayer方法加载图标是静态的&#xff0c;如果用div的话&#xff0c;400个就会很卡顿 解决方案&#xff1a; 目前BillboardEntity加载是静态的&#xff0c;无法加载动图&#xff0c;网上搜了下&#xff0c;可以使用apngjs.js…

javaSE练习题(一)

1、BMI是根据体重测量健康的方式。通过以千克为单位的体重除以以米为单位的身高的平方计算出BMI。下面是16 岁以上人群的BMI图表: 编写一个java程序&#xff0c;提示用户输人以磅为单位的体重和以英寸为单位的身高&#xff0c;然后显示BMI值。注意: 1磅是0.453592 37千克而1英寸…

GPU云服务器的优势和应用

GPU即图形处理器&#xff0c;是一种高性能计算加速器&#xff0c;主要用于处理复杂的图像、视频等。GPU云服务器&#xff0c;指的是在云计算环境下&#xff0c;通过云平台提供GPU计算能力的虚拟服务器。随着科技的迅猛发展&#xff0c;科技领域对其的讨论和应用也日益热烈、广泛…

高德地图——轨迹回放和电子围栏

功能点 地图的初始化显示电子围栏(先初始化在调接口显示电子围栏)显示定位显示轨迹轨迹回放 (回放速度无法控制是因为高德地图的版本问题,不要设置版本,使用默认的即可生效)获取当前城市及天气情况设置地图样式坐标拾取器重点 默认当前城市地图加载完成的生命周期this.ma…

Linux课程____进程管理

记录工作日志 script 240319.log CTRLd 退出 cat 240319.log //查看 一、查看进程 1.静态 ps -aux ps -elf 2.动态 top 3.pgrep 查看特定条件的进程 pgrep -l “log” pgrep -l "ssh" pgrep -l -U redhat 4.pstree 查看进程树 pstree -aup 所有…

element plus等框架中属性值是组件如何传入,替换分页图标

在 Vue 中替换element plus 分页图标 正常写法引入组件 import prevIcon from /components/xx.vue;<el-pagination layout"prev, pager, next" :prev-icon"prevIcon" :total"5" />利用 h 函数写法 const prevIcon h(div, [xr]);可以写…

排序算法:归并排序(递归)

文章目录 一、归并排序的思路二、代码编写 先赞后看&#xff0c;养成习惯&#xff01;&#xff01;&#xff01;^ _ ^<3 ❤️ ❤️ ❤️ 码字不易&#xff0c;大家的支持就是我坚持下去的动力。点赞后不要忘了关注我哦&#xff01; 所属专栏:排序算法 一、归并排序的思路 单…

第二话 让屏幕显示想要的东西

上一话搭建了可说是可以开发了 接下来想办法 让 屏幕显示想要的东西 但是报错: ************************************************************************** * Looking for Adafruit_ILI9341.h dependency? Check our library registry! * * CLI > platformio lib se…

【DataWhale学习笔记-蝴蝶书共读】大语言模型背后

从图灵测试到ChatGPT 1950年&#xff0c;艾伦•图灵(Alan Turing)发表论文《计算机器与智能》&#xff08; Computing Machinery and Intelligence&#xff09;&#xff0c;提出并尝试回答“机器能否思考”这一关键问题。在论文中&#xff0c;图灵提出了“模仿游戏”&#xff…

AD软件中怎么添加不同元素之间的间距规则呢

AD软件中怎么添加不同元素之间的间距规则呢 答&#xff1a;AD软件提供了某一个元素针对其他元素之间的间距规则的设置。 首先执行菜单命令【设计】-【规则】或者快捷键DR打开规则约束编辑器&#xff0c;然后在间距规则Clearance里面添加一个新的规则&#xff0c;如图1所示 图…

阅读MySQL知识2

1、三大范式 2、DML 语句和 DDL 语句区别 3、主键和外键的区别 4、drop、delete、truncate 区别 5、基础架构 6、MyISAM 和 InnoDB 有什么区别&#xff1f; 7、推荐自增id作为主键问题 8、为什么 MySQL 的自增主键不连续 9、redo log 是做什么的? 10、redo log 的刷盘…

19---时钟电路设计

视频链接 时钟硬件电路设计01_哔哩哔哩_bilibili 时钟电路设计 晶振是数字电路的心脏&#xff0c;数字电路需要一个稳定的工作时钟信号&#xff0c;时钟电路至关重要&#xff01; 1、晶振概述 晶振一般指晶体振荡器。晶体振荡器是指从一块石英晶体上按一定方位角切下薄片&…

H6603实地架构降压芯片100V耐压 80V 72V 60V 48V单片机/模块供电应用

H6603 是一款内置功率 MOSFET降压开关转换器。在宽输入范围内&#xff0c;其最大持续输出电流 0.8A&#xff0c;具有极好的负载和线性调整率。电流控制模式提供了快速瞬态响应&#xff0c;并使环路更易稳定。故障保护包括逐周期限流保护和过温保护。H6603 最大限度地减少了现有…