Класс Matrix оцените реализацию

231
28 августа 2017, 06:44

Часто слышал про задачки, типо реализуйте класс для матриц, комплексных чисел и т.д. Вот, наконец-то, попробовал. Меня интересует мнение, хорошо ли он реализован? Может можно как-то по другому и куда собственно двигаться дальше? Можно ли как-то усложнить реализацию? И где можно найти задачи где нужно не только реализовывать алгоритмы (то есть сплошная математика), а еще и пользоваться возможностями языка (наследования, обобщения, обработка исключений и т.д.).

package matrix;
public class Matrix {
    private final int rows;
    private final int columns;
    private int[][] matrix;
    /****************** Constructors ******************/
    public Matrix() {
        this.rows    = 1;
        this.columns = 1;
        this.matrix  = new int[rows][columns];
    }
    public Matrix(int rows, int columns) throws MatrixException {
        if(rows <= 0 || columns <= 0) {
            throw new MatrixException("Заданы неверные размеры матрицы");
        }
        this.rows    = rows;
        this.columns = columns;
        this.matrix  = new int[rows][columns];
    }
    public Matrix(int size) throws MatrixException {
        if(size <= 0) {
            throw new MatrixException("Заданы неверные размеры матрицы");
        }
        this.rows = this.columns = size;
        this.matrix = new int[size][size];
    }
    public Matrix(int[][] matrix) {
        this.rows    = matrix.length;
        this.columns = matrix[0].length;
        this.matrix  = matrix;
    }
    /************************************************************************/
    public static final Matrix sum(Matrix matrix1, Matrix matrix2) throws MatrixException {
        if(!check(matrix1, matrix2, false)) {
            throw new MatrixException("Размеры матриц не совпадают");
        }
        else {
            int size;
            if(!matrix1.checkSquare()) {
                size = matrix1.rows > matrix1.columns ? matrix1.columns : matrix1.rows;
            }
            else {
                size = matrix1.rows;
            }
            Matrix matrix = new Matrix(size);
            for(int i = 0; i < matrix1.rows; i++) {
                for(int j = 0; j < matrix1.columns; j++) {
                    matrix.matrix[i][j] = matrix1.matrix[i][j] + matrix2.matrix[i][j];
                }
            }
            return matrix;
        }
    }
    public static final Matrix multiply(Matrix matrix1, Matrix matrix2) throws MatrixException {
        if(!check(matrix1, matrix2, true)) {
            throw new MatrixException("Размеры матриц не совпадают");
        }
        else {
            int size;
            int n;
            if(!matrix1.checkSquare()) {
                size = matrix1.rows > matrix1.columns ? matrix1.columns : matrix1.rows;
                n = matrix1.rows > matrix1.columns ? matrix1.rows : matrix1.columns;
            }
            else {
                size = matrix1.rows;
                n = matrix1.rows;
            }
            Matrix matrix = new Matrix(size);
            matrix.fill(0);
            for(int i = 0; i < size; i++) {
                for(int j = 0; j < size; j++) {
                    for(int k = 0; k < n; k++) {
                        matrix.matrix[i][j] += matrix1.matrix[i][k]*matrix2.matrix[k][j];
                    }
                }
            }
            return matrix;
        }
    }
    public final void print() {
        for(int i = 0; i < rows; i++) {
            for(int j = 0; j < columns; j++) {
               System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
    }
    public final void fill(int number) {
        for(int i = 0; i < rows; i++) {
            for(int j = 0; j < columns; j++) {
                matrix[i][j] = 0;
            }
        }
    }
    private final static boolean check(Matrix matrix1, Matrix matrix2, boolean forMultiply) {
        if(forMultiply) {
            return ((matrix1.rows == matrix2.rows) && (matrix1.columns == matrix2.columns)) ||
                    (matrix1.columns == matrix2.rows);
        }
        else {
            return (matrix1.rows == matrix2.rows) && (matrix1.columns == matrix2.columns);
        }
    }
    public final boolean checkSquare() {
        return rows == columns;
    }
}
package matrix;
public class MatrixException extends Exception {
    private String cause;
    MatrixException(String cause) {
        this.cause = cause;
    }
    public String cause() {
        return this.cause;
    }
}
Answer 1

В целом код мне понравился, вот несколько моментов, которые я бы переделал (это моё субъективное мнение, для краткости я не стал добавлять в каждое предложение слова "Мне кажется, что ..."):

  1. Рассмотрим метод check. Он принимает два параметра и булевый флаг, и в зависимости от флага выполняет два разных кода. Что если вы добавите к операциям сложения и умножения третью операцию? Как тогда будет определяться, какую из трёх проверок делать (не передавать же два флага)? Лучше разделить этот метод на два, checkSum и checkMultiply. Ещё лучше убрать эти методы (они всё равно используются только в методах sum и multiply) и занести код проверок внутрь методов sum и multiply, так код станет понятней.

  2. Рассмотрим фрагмент кода в методе sum:

    int size;
    if (!matrix1.checkSquare()) {
        size = matrix1.rows > matrix1.columns ? matrix1.columns : matrix1.rows;
    } else {
        size = matrix1.rows;
    }
    

    начнём с этой строчки:

    size = matrix1.rows > matrix1.columns ? matrix1.columns : matrix1.rows;
    

    тут берётся минимум из matrix1.columns и matrix1.rows. Если переписать через Math.min, получится лучше:

    if (!matrix1.checkSquare()) {
        size = Math.min(matrix1.rows, matrix1.columns);
    } else {
        size = matrix1.rows;
    }
    

    далее, подумаем, нужен ли нам вообще if? Если матрица квадратная, то matrix1.rows == matrix1.columns и вариант кода для неквадратной матрицы корректно обработает этот случай. Таким образом фрагмент можно сократить до

    int size = Math.min(matrix1.rows, matrix1.columns);
    
  3. Далее, зачем нам вообще в методе sum было вычислять минимум из размерностей матриц? Если матрицы неквадратные, то где-то дальше по коду возникнет исключение ArrayIndexOutOfBoundsException. Возможно вместо минимума должен вычисляться максимум, но это тоже не очень хорошо: почему суммой двух матриц должна обязательно быть квадратная матрица? ЛУчше если суммой двух матриц будет матрица такой же размерности. Поэтому я бы переписал метод вот так:

    public static final Matrix sum(Matrix matrix1, Matrix matrix2) throws MatrixException {
        if (matrix1.rows != matrix2.rows || matrix1.columns != matrix2.columns) {
            throw new MatrixException("Размеры матриц не совпадают");
        } else {
            Matrix matrix = new Matrix(matrix1.rows, matrix1.columns);
            for(int i = 0; i < matrix1.rows; i++) {
                for(int j = 0; j < matrix1.columns; j++) {
                    matrix.matrix[i][j] = matrix1.matrix[i][j] + matrix2.matrix[i][j];
                }
            }
            return matrix;
        }
    }
    
  4. Метод multiply также всегда возвращает квадратную матрицу, стоит исправить, чтобы для матриц размера n x m и m x k возвращал матрицу n x k.

  5. Рассмотрим метод fill(int number):

    public final void fill(int number) {
        for(int i = 0; i < rows; i++) {
            for(int j = 0; j < columns; j++) {
                matrix[i][j] = 0;
            }
        }
    }
    

    здесь небольшая опечатка, вместо заполнения матрицы числом number происходит заполнение матрицы нулями.

  6. Метод checkSquare лучше назвать isSquare

READ ALSO
Отслеживание загрузки классов

Отслеживание загрузки классов

Есть приложение desktop на javaХочу сделать картинку предзагрузки

279
Использование JQuery и JSF

Использование JQuery и JSF

Есть таблица в xhtml файле на JFSТребуется, при помощи JQuery проверить значения в ячейках конкретного столбца и при совпадении с образцом изменить...

264