Algoritmo de transposición rápida de matriz dispersa Java_ (+ experiencia de depuración)

Categoria principal

/*
* @Description:
* @Version: 2.0
* @Author: xuchaoxin
* @Date: 2021-03-09 19:27:00
 * @LastEditors: xuchaoxin
 * @LastEditTime: 2021-03-10 20:47:09
*/

import java.util.ArrayList;
import java.util.TreeMap;

/**
 * @Author xuchaoxin
 * @Date 2021/3/9 21:00
 * @Version 1.0 the detail and improved version(if I update it ) to see: the
 * github repository (search the
 * article):https://github.com/xuchaoxin1375/LearnJava
 */
public class main {
    
    
    /**
     * 主函数,测试这个系统的功能*/
public static void main(String[] args) {
    
    
    /*创建可以读取矩阵的对象*/
    InputMatrix inputMatrix = new InputMatrix();
    /*读取矩阵*/
    SparseMatrix sparseMatrix1 = inputMatrix.getSparseMatrix();
    /*执行转置,并打印矩阵*/
    translate(sparseMatrix1).print();

}
/**调度各个功能方法,得到以行优先顺序的稀疏矩阵的元素(三元组)所构成的列表所构成的对象:SparseMatrix*/
static SparseMatrix translate(SparseMatrix sparseMatrix1) {
    
    
    /**
     *
     * 快速转置算法充分利用了Triple结构中的坐标成员 实质是对三元组列表中的元素进行调序(某种规则下的重排序),以得到一个等长度的新列表
     *
     * 目的是求得转置后的三元组列表(即计算该列表中的(非零)元素是怎么排列的),而不是直接区计算得到二维分布(届时写一个解压函数来将位置分布呈现出来)
     */
    SparseMatrix sparseMatrix2 = new SparseMatrix();
    setProfile(sparseMatrix1, sparseMatrix2);
    /*定义计数器(注意,有必要指明该计数器中保存的值表示什么:保存的是转置矩阵各行所具有的非零元素个数
    * 那么,第一行是从0计还是从1计数?
    * 这里就规定,从0行开始计数,那么统计过程中各个元素的坐标也要从0开始计数*/
    int[] elementNumOfEachRow2 = new int[sparseMatrix1.ncol];
    /*初始换计数器*/
    for (int i = 0; i < sparseMatrix1.ncol; i++) {
    
    
        elementNumOfEachRow2[i] = 0;
    }
    /* 统计转置后的矩阵的各个行中具有的非零元素的个数 */
    for (int i = 0; i < sparseMatrix1.num; i++) {
    
    
        /*调试需要:*/

        elementNumOfEachRow2[sparseMatrix1.getTriple(i).col - 1]++;
        System.out.println(sparseMatrix1.getTriple(i));
    }
    /*  */
    int[] startInsertArray = divideZone(sparseMatrix1, elementNumOfEachRow2);
    getResortTripleList(startInsertArray, sparseMatrix1, sparseMatrix2);

    return sparseMatrix2;

}
/**设置转置矩阵总体SparseMatrix对象包含的信息参数*/
static void setProfile(SparseMatrix sparseMatrix1, SparseMatrix sparseMatrix2) {
    
    
    sparseMatrix2.ncol = sparseMatrix1.nrow;
    sparseMatrix2.nrow = sparseMatrix1.ncol;
    sparseMatrix2.num = sparseMatrix1.num;
}

/** 将转置矩阵的三元组数组以各个行中具有的非零元素数目为标准,做相应分区划段,来存储各行中的元素;需要划分的段数为转置前矩阵的列数 */
static int[] divideZone(SparseMatrix sparseMatrix, int[] elementNumOfEachRow2) {
    
    

    int[] startInsertArray = new int[sparseMatrix.ncol];
    startInsertArray[0] = 0;// 初始化第一个值,手动初始化指明(从[0]个位置开始插入),为地推做准备
    for (int i = 1; /* i表示为转置矩阵的每一行计算其区间段的宽度(以存放对应行的非零元素) */
            i < sparseMatrix.ncol; i++) {
    
    
        startInsertArray[i] = startInsertArray[i - 1] + elementNumOfEachRow2[i - 1];
    }

    return startInsertArray;
}
/** 调序插入到转置矩阵中的三元组列表中(核心步骤) */
static void getResortTripleList(int[] startInsertArray, SparseMatrix sparseMatrix1, SparseMatrix sparseMatrix2) {
    
    
    /*提取常用表达式的计算结果,简化代码*/
    int position;
    Triple elementPoint, srcElementPoint;
    /*批量生成Triple对象*/
    for (int j = 0; j < sparseMatrix2.num; j++) {
    
    
        sparseMatrix2.tripleList.add(new Triple());
    }
    for (int i = 0; i < sparseMatrix1.num; i++) {
    
    
        /* 先计算当前非零元素在转置三元组列表中会落在那个区间(左边界) */
        position = getPosition(i, startInsertArray, sparseMatrix1);
        /*检查position的值:  */
        System.out.println(position);

        elementPoint = sparseMatrix2.getTriple(position);

        srcElementPoint = sparseMatrix1.getTriple(i);
        /* 以下该值操作不影响原矩阵中的三元组 */
        elementPoint.setRow(srcElementPoint.getCol());
        elementPoint.setCol(srcElementPoint.getRow());
        elementPoint.setData(srcElementPoint.getData());
        /* 修改该元素所在行的下一个元素要插入的位置(虽然不一定还会有) */
        updateStartInsertArray(i, startInsertArray, sparseMatrix1);
    }

}

/** 用于计算原始矩阵(三元组列表)中各个元素转置到新矩阵中时会在第几行,并依此计算在该元素所在的行在转置矩阵对象中的三元组列表的起始插入位置索引
* 应当配和updateStartInsertArray()方法,来确保当同一行的非零元素有多个时的情况能够正确计算索引并插入
* 当然这两个方法不是必须的,可以都嵌在translate方法中,这里只是为例划分逻辑*/
static int getPosition(int index, int[] startInsertArray, SparseMatrix sparseMatrix1) {
    
    
    return startInsertArray[sparseMatrix1.getTriple(index).getCol()-1];

}
/**更新插入到转置矩阵三元组列表中索引值(针对当同一行非零元素不知1个时所作出的索引引导修正)*/
static void updateStartInsertArray(int index, int[] startInsertArray, SparseMatrix sparseMatrix1) {
    
    
    startInsertArray[sparseMatrix1.tripleList.get(index).col-1]++;
}

}
/**三元组中各个非零元素的类*/
class Triple {
    
    
/**
 * 稀疏矩阵中的单个元素包含的信息
 */
int row; /* 横坐标 */
int col; /* 纵坐标 */
int data;/* 值 */

@Override
/**用于调试打印元素信息使用:*/
public String toString() {
    
    
    return "Triple{" +
            "row=" + row +
            ", col=" + col +
            ", data=" + data +
            '}';//+"注意这里坐标是从1计数";

}

/**javaBean 基本操作系列*/
public int getRow() {
    
    
    return this.row;
}

public void setRow(int row) {
    
    
    this.row = row;
}

public int getCol() {
    
    
    return this.col;
}

public void setCol(int col) {
    
    
    this.col = col;
}

public int getData() {
    
    
    return this.data;
}

public void setData(int data) {
    
    
    this.data = data;
}

}

/**稀疏矩阵整体的数据结构(保存的是压缩成三元组数组/列表的形式) */
class SparseMatrix {
    
    
public void setTripleList(ArrayList<Triple> tripleList) {
    
    
    this.tripleList = tripleList;
}

public void setNrow(int nrow) {
    
    
    this.nrow = nrow;
}

public void setNcol(int ncol) {
    
    
    this.ncol = ncol;
}

public void setNum(int num) {
    
    
    this.num = num;
}

ArrayList<Triple> tripleList = new ArrayList<>();
int nrow, /* 矩阵的行数 */
        ncol, /* 矩阵的列数 */
        num;

Triple getTriple(int index) {
    
    
    return tripleList.get(index);
}
/**解压打印稀疏矩阵(中的三元组列表),非静态方法不需要设置参数*/
void print(/*SparseMatrix sparseMatrix*/) {
    
    
    int[][] matrix = new int[nrow][ncol];

    /*填充数组*/
    for (int i = 0; i < num; i++) {
    
    
        Triple triple = getTriple(i);
        if (triple.getData() != 0) {
    
    
            matrix[triple.getRow()-1][triple.getCol()-1] = triple.getData();
        }
    }
    /*打印矩阵(二维数组)*/
    for (int i = 0; i < nrow; i++) {
    
    
        for (int j = 0; j < ncol; j++) {
    
    
            System.out.print(matrix[i][j]+" ");
        }
        System.out.println();
    }
}
}

Clase de función auxiliar (leída en una matriz de cualquier especificación)

/*
 * @Description:
 * @Version: 2.0
 * @Author: xuchaoxin
 * @Date: 2021-03-10 16:24:37
 * @LastEditors: xuchaoxin
 * @LastEditTime: 2021-03-10 17:35:31
 */

import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class InputMatrix {
    
    
    /**
     * 读入矩阵(任意长度和宽度) 以两个连续的enter键来结束矩阵的输入
     */
    public static int[][] ReadMatrix() {
    
    
        /* 代开输入流(标准输入流) */
        Scanner sc = new Scanner(System.in);
        /* 建立二重列表 */
        List<List<String>> lists = new ArrayList<>();
        /* 定义一个字符串行 */
        String Line = null;
        /* 循环读入并处理每一行数据 */
        while ((Line = sc.nextLine()).length() != 0) {
    
    
            /**
             * 当读入的内容不为空(可以用字符串长度来判断),则读入并添加到list中
             */
            lists.add(Arrays.asList(Line.trim().split(" ")));
            /**
             * 这里String对象的 split()方法返回String[]数组
             * 将数组Line.trim().split()作为Arrays.asList()方法作为参数,返回一个List public static <T>
             * List<T> asList(T... a) { return new ArrayList<>(a); }
             */
        }
        /* 读取完毕,关闭输入流 */
        sc.close();
        /* 转为二维数组 */
        int m = lists.size();// 相当于行数
        int n = lists.get(0).size();// 相当于列数:lists.get(0)为第一行输入
        int[][] matrix = new int[m][n];
        // 将字符串变为int类型
        for (int i = 0; i < m; i++) {
    
    
            for (int j = 0; j < n; j++) {
    
    
                matrix[i][j] = Integer.parseInt(lists.get(i).get(j));
            }
        }
        return matrix;
    }

    /**矩阵压缩*/
    public SparseMatrix getSparseMatrix(/*int[][] matrix*/) {
    
    
        int[][] matrix = ReadMatrix();
        int nrow = matrix.length;
        int ncol = matrix[0].length;
        SparseMatrix sparseMatrix = new SparseMatrix();
        int count = 0;
        /*注意,这里索引变量从0开始*/
        for (int i = 0; i < nrow; i++) {
    
    
            for (int j = 0; j < ncol; j++) {
    
    
                if (matrix[i][j] != 0) {
    
    
                    count++;
                    Triple triple = new Triple();
                    /*转化为从1开始计数的坐标(根据需要)*/
                    triple.setRow(i+1);
                    triple.setCol(j+1);
                    triple.setData(matrix[i][j]);
                    sparseMatrix.tripleList.add(triple);
                }
            }
        }
        sparseMatrix.setNum(count);
        sparseMatrix.setNrow(nrow);
        sparseMatrix.setNcol(ncol);
        return sparseMatrix;
    }

    // 打印验证
    public static void main(String[] args) {
    
    
//        int[][] matrix = ReadMatrix();
        System.out.println("test:...");
/*        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println("\n");
        }*/
        InputMatrix inputMatrix=new InputMatrix();
        inputMatrix.getSparseMatrix().print();

    }
}

Experiencia de escritura y depuración

Debemos tener claro que aunque la depuración es muy importante, no debería ser fácil. Siempre depende de la depuración. Es fácil provocar una codificación descuidada. Después de todo, depurar (esto lleva mucho tiempo)
Debemos ser lo más precisos posible cuando codificación.La definición de cualquier variable u objeto, o incluso cada función y método, debe tener un propósito muy claro, sin la más mínima ambigüedad, los comentarios de la documentación deben mantener esta idea para que las verificaciones del algoritmo se brinden para atravesar incluso al depurar
el Es especialmente importante que el mismo sistema de medición (si no puede ser el mismo globalmente, debe ser el mismo que el módulo, y se agrega el sistema de medición / sistema de referencia necesario). Por
ejemplo, en el problema de cálculo de matriz de dos dígitos / matriz, las coordenadas de un solo elemento se cuentan desde 1. En una matriz de dos dígitos, la siguiente tabla comienza a contar desde 0. No confunda los dos lugares.
Debe desarrollar el hábito de describir claramente los requisitos y luego escribir la función correspondiente. Si el propósito del
método / función
es más complicado, no debería reflejarse completamente en El nombre del método
se puede abreviar, pero recuerde escribir claramente la documentación de uso de la función.
Si solo escribe un programa pequeño, no se limite demasiado a subcontratar la función.Puede
dividir la función de código en bloques (la asignación de tareas funcionales se refleja en la forma de comentarios del documento para reflejar la lógica De la
misma manera, puede hacer esto al escribir un método grande.
Al crear variables para guardar expresiones más largas, puede reducir los cálculos repetitivos y el código puede ser más conciso, intuitivo y eficiente.

Supongo que te gusta

Origin blog.csdn.net/xuchaoxin1375/article/details/114649656
Recomendado
Clasificación