Typescript 实现矩阵类,包含矩阵与矩阵的四则运算,矩阵与实数的乘法;矩阵的余子式与代数余子式计算,方阵的行列式计算,伴随矩阵计算,方阵的逆矩阵计算,转置矩阵等。
对于是否是方阵没有作多于判断(懒
方法注释在代码中都有
class Matrix {
private mm: Array<Array<number>>;
private _row: number;
private _col: number;
/**
* 可以使用一个二维数组赋值给 mat 以修改矩阵。修改矩阵会同时修改行数列数的变量
*/
set mat(arr: Array<Array<number>>) {
this.mm = this.dim2ArrDeepCopy(arr);
this._row = this.mm.length;
this._col = this.mm[0].length;
}
/**
* Matrix 构造函数,返回所有元素为0的矩阵。当传入1个参数时,为方阵
* @param{number}row_num 行数
* @param{number}col_num 列数
*/
constructor(row_num: number, col_num?: number) {
this.mm = [];
this._row = row_num;
if (col_num) {
this._col = col_num;
for (let i = 0; i < row_num; i++) {
this.mm.push([]);
for (let j = 0; j < col_num; j++) {
this.mm[i][j] = 0;
}
}
}
else {
this._col = row_num;
for (let i = 0; i < row_num; i++) {
this.mm.push([]);
for (let j = 0; j < row_num; j++) {
this.mm[i][j] = 0;
}
}
}
}
/**
* 深拷贝二维数组
* @param{Array<Array<number>>}arr 所要拷贝的二维数组
* @returns 返回拷贝的二维数组
*/
private dim2ArrDeepCopy(arr: Array<Array<number>>): Array<Array<number>> {
let tmp: Array<Array<number>> = [];
for (let i = 0; i < arr.length; i++) {
tmp.push([]);
for (let j = 0; j < arr[0].length; j++) {
tmp[i][j] = arr[i][j];
}
}
return tmp;
}
/**
* 得到矩阵对应地二维数组的深拷贝
* @returns 矩阵对应的二维数组
*/
public getArr(): Array<Array<number>> {
/* let tmp: Array<Array<number>> = [];
for (let i = 0; i < this._row; i++) {
tmp.push([]);
for (let j = 0; j < this._col; j++) {
tmp[i][j] = this.mm[i][j];
}
} */
let tmp = this.dim2ArrDeepCopy(this.mm);
return tmp;
}
/**
* 深拷贝一个矩阵实例
* @param{Matrix}m 拷贝对象
*/
public copy(m: Matrix): void {
this.mat = m.mm;
}
/**
* 遍历矩阵并用函数修改值
* @param{Function}fn 可传入3个参数: 1.修改的值 2.行索引 3.列索引
*/
public mapMat(fn: Function): void {
for (let i = 0; i < this._row; i++) {
for (let j = 0; j < this._col; j++) {
// this.mm[i][j] = fn(this.mm[i][j], i, j);
fn(this.mm[i][j], i, j) &&
this.setMatVal(i + 1, j + 1, fn(this.mm[i][j], i, j));
}
}
}
/**
* 修改矩阵指定行列的值
* @param{number}row 指定行
* @param{number}col 指定列
* @param{number}value 值
*/
public setMatVal(row: number, col: number, value: number) {
this.mm[row - 1][col - 1] = value;
}
/**
* 打印矩阵 用' '和'\n'隔开
*/
public show(): void {
let s: string = '';
for (let i = 0; i < this._row; i++) {
for (let j = 0; j < this._col; j++) {
s += this.mm[i][j];
if (j < this._col - 1) s += ' ';
}
if (i < this._row - 1) s += '\n';
}
console.log(s);
}
/**
* 求方阵的行列式结果。所求矩阵必须行列数相等
* @returns 行列式结果
*/
public det(): number {
if (this._row == 1 && this._col == 1) {
return this.mm[0][0];
}
const r = 1; // 取第1行
let result: number = 0;
for (let i = 1; i <= this._col; i++) {
result += this.mm[r - 1][i - 1] * this.alCofactor(r, i);
}
return result;
}
/**
* 求余子式
* @param{number}row 指定行
* @param{number}col 指定列
* @returns{number}余子式结果
*/
public cofactor(row: number, col: number) {
let tmpMat: Matrix = new Matrix(this._row - 1, this._col - 1);
for (let i = 0; i < this._row; i++) {
let _i;
if (i + 1 < row) _i = i;
else if (i + 1 > row) _i = i - 1;
else _i = -1;
for (let j = 0; j < this._col; j++) {
let _j;
if (j + 1 < col) _j = j;
else if (j + 1 > col) _j = j - 1;
else _j = -1;
if (_i == -1 || _j == -1) continue;
tmpMat.mm[_i][_j] = this.mm[i][j];
}
}
return tmpMat.det();
}
/**
* 求代数余子式
* @param{number}row 指定行
* @param{number}col 指定列
* @returns{number}代数余子式结果
*/
public alCofactor(row: number, col: number) {
let c = this.cofactor(row, col);
if ((row + col) % 2 == 0) return c;
else return -c;
}
/**
* 矩阵加法,会改变自身。
* @param{Matrix}m2 所加的矩阵。行列数必须与调用者行列数相等
* @returns 改变后的调用者
*/
public plus(m2: Matrix): Matrix {
// 必须行列相等
this.mapMat((el: number, i: number, j: number): number => el + m2.mm[i][j]);
return this;
}
/**
* 矩阵加法的静态方法
* @param{Matrix}m1 矩阵1
* @param{Matrix}m2 矩阵2
* @returns 结果矩阵的实例
*/
public static plus(m1: Matrix, m2: Matrix): Matrix {
// 两个矩阵必须行列相等
let resMat = new Matrix(m1._row, m1._col);
resMat.mapMat((el: number, i: number, j: number) => m1.mm[i][j] + m2.mm[i][j]);
return resMat;
}
/**
* 矩阵减法,会改变自身
* @param{Matrix}m2 被减矩阵。行列数必须与调用者行列数相等
* @returns 改变后的调用者
*/
public minus(m2: Matrix): Matrix {
this.mapMat((el: number, i: number, j: number): number => el - m2.mm[i][j]);
return this;
}
/**
* 矩阵减法的静态方法
* @param{Matrix}m1 矩阵1
* @param{Matrix}m2 矩阵2
* @returns 结果矩阵的实例
*/
public static minus(m1: Matrix, m2: Matrix): Matrix {
// 两个矩阵必须行列相等
let resMat = new Matrix(m1._row, m1._col);
resMat.mapMat((el: number, i: number, j: number) => m1.mm[i][j] - m2.mm[i][j]);
return resMat;
}
/**
* 右乘矩阵,会改变自身
* @param{Matrix}m2 被乘矩阵。行数必须与调用者列数相等
* @returns 改变后的调用者
*/
public multMat(m2: Matrix): Matrix {
// 行数 = m2的列数
let resMat: Matrix = new Matrix(this._row, m2._col);
resMat.mapMat((el: number, i: number, j: number): number => {
let tmp = 0;
for (let ii = 0; ii < this._col; ii++) {
tmp += this.mm[i][ii] * m2.mm[ii][j];
}
return tmp;
})
this.copy(resMat);
return this;
}
/**
* 矩阵乘矩阵的静态方法 m1*m2
* @param{Matrix}m1 矩阵1
* @param{Matrix}m2 矩阵2
* @returns 结果矩阵的实例
*/
public static multMat(m1: Matrix, m2: Matrix): Matrix {
let resMat: Matrix = new Matrix(m1._row, m2._col);
resMat.mapMat((el: number, i: number, j: number): number => {
let tmp = 0;
for (let ii = 0; ii < m1._col; ii++) {
tmp += m1.mm[i][ii] * m2.mm[ii][j];
}
return tmp;
})
return resMat;
}
/**
* 矩阵乘一个实数,会改变自身
* @param{number}n 乘数
* @returns 改变后的调用者
*/
public multNum(n: number): Matrix {
this.mapMat((el: number, i: number, j: number): number => el * n);
return this;
}
/**
* 矩阵乘一个实数的静态方法
* @param{Matrix}m 矩阵
* @param{number}n 乘数
* @returns 结果矩阵的实例
*/
public static multNum(m: Matrix, n: number): Matrix {
let resMat: Matrix = new Matrix(m._row, m._col);
resMat.copy(m);
resMat.mapMat((el: number, i: number, j: number): number => el * n);
return resMat;
}
/**
* 伴随矩阵
* @returns{Matrix}伴随矩阵的实例
*/
public adjointMat(): Matrix {
let adMat = new Matrix(this._col, this._row);
adMat.mapMat((el: number, i: number, j: number): number => this.alCofactor(j + 1, i + 1));
return adMat;
}
/**
* 逆矩阵。必须为方阵,且行列式不为0
* @returns{Matrix}逆矩阵的实例
*/
public inv(): Matrix | undefined {
if (this.det() == 0) {
console.log('该方阵行列式为0,逆矩阵不存在!');
return;
}
let adMat = this.adjointMat();
adMat.multNum(1 / this.det());
return adMat;
}
/**
* 构造一个指定大小的单位矩阵
* @param{number}n 单位矩阵维数
* @returns 单位矩阵实例
*/
public static eye(n: number): Matrix {
let resMat = new Matrix(n);
resMat.mapMat((el: number, i: number, j: number) => {
if (i == j) return 1;
})
return resMat;
}
/**
* 求转置矩阵
* @returns 转置矩阵实例
*/
public T(): Matrix {
let resMat = new Matrix(this._col, this._row);
resMat.mapMat((el: number, i: number, j: number) => this.mm[j][i]);
return resMat;
}
}
使用很简单
初始化,每个元素随机值
?实例方法和静态方法的四则运算
可链式调用
转置矩阵
求行列式和逆矩阵
行列式为0时逆矩阵不存在
余子式在逆矩阵中有使用,不做单独演示。
因为二维矩阵比较好观察正确率,所以演示使用二维矩阵。矩阵与其逆矩阵相乘时,可能结果不为单位矩阵,有细微的误差,这和计算精度相关非算法问题。精度方面这里没做过多考虑。
有问题欢迎指正~
|