[TypeScript] 实现简单矩阵类

[TypeScript] 实现简单矩阵类,第1张

Typescript 实现矩阵类,包含矩阵与矩阵的四则运算,矩阵与实数的乘法;矩阵的余子式与代数余子式计算,方阵的行列式计算,伴随矩阵计算,方阵的逆矩阵计算,转置矩阵等。

对于是否是方阵没有作多于判断(懒

方法注释在代码中都有

class Matrix {
    private mm: Array>;
    private _row: number;
    private _col: number;

    /**
     * 可以使用一个二维数组赋值给 mat 以修改矩阵。修改矩阵会同时修改行数列数的变量
     */
    set mat(arr: Array>) {
        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>}arr 所要拷贝的二维数组
     * @returns 返回拷贝的二维数组
     */
    private dim2ArrDeepCopy(arr: Array>): Array> {
        let tmp: Array> = [];
        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> {
        /* let tmp: Array> = [];
        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时逆矩阵不存在

余子式在逆矩阵中有使用,不做单独演示。

因为二维矩阵比较好观察正确率,所以演示使用二维矩阵。矩阵与其逆矩阵相乘时,可能结果不为单位矩阵,有细微的误差,这和计算精度相关非算法问题。精度方面这里没做过多考虑。

有问题欢迎指正~

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/940651.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-17
下一篇 2022-05-17

发表评论

登录后才能评论

评论列表(0条)

保存