日撸 Java 三百行(07天,Java的数组与矩阵元素相加)
今天通过矩阵认识java有关的数组操作以及相关动态创建方法
一、必要准备
1.关于动态创建
这得注意,java中的数组声明方案实际上是有两个的,传统的方法是:
dataType arrayRefVar[];
这个方法继承了C与C++的衣钵,Java源文档中也特别说明此方案是为方便原C与C++程序员能尽快适应java语言。但是这种方案并不常用,很不“java”。
现在更常用的数组声明方案是:
dataType[] arrayRefVar;
这个方案很像C#,但是其实历史上C#是微软与SUN公司(出品java的公式)闹掰之后自己仿造java创立的语言,所以也许说C#的数组声明的来源正是来自这也说不定。
声明完毕后需要为数组动态分配空间,其中动态分配方法来源于C++的new方法:
dataType[] arrayRefVar = new dataType[arraySize];
这个语句做了什么呢?
1.使用dataType[arraySize]创建了一个数组
2.把创建的数组的引用赋值给变量 arrayRefVar
那么,如果要创建多维数组呢?只需要修改数据类型即可:
dataType[][] arrayRefVar = new dataType[arrayHeight][arrayWidth];
插一句静态创建
最后提一句,动态创建不是唯一的创建方案,数组的静态创建也是常用的,其风格与C语言系列类似,可通过在[ ]写入确定量或者用{ }取等预定元素都是可以的:
dataType[10] arrayRefVar1;
dataType[10][20] arrayRefVar1;
double[] arrayRefVar2 = {1.2, 2.3, 3.4};
2.Arrays 类
Arrays类提供了众多方便使用的方法,以下介绍一些可用方法:
public static int binarySearch(Object[] a, Object key)
用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;
排序数组最频繁的操作之一,也是任何语言学数组都需要了解的基本
public static void sort(Object[] a)
对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
Arrays.sort(tempArrays); //正序排tempArrays
Arrays.sort(tempArrays,Collections.reverseOrder()); //逆序排tempArrays
Arrays.sort(tempArrays, i, j);//正序对tempArrays的i到j位置进行排序
自定义复写cmp函数实现自定义排序可参考https://blog.csdn.net/qq_36785612/article/details/79935552
填充操作是非常常用的初始化操作,许多算法的常客
public static void fill(int[] a, int val)
将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
补充:另一种格式Arrays.fill(int[] array,int from,int to,int val)可以实现区域填充
数组我们进程就使用来说,会用for来遍历,但是如果只是想看数据内容的话,专门使用for与print来混合完成未免有些麻烦了。于是java库中提供类一些常见的快捷查看用的输出方法:
Arrays.toString(Object[] array)
功能:返回数组的字符串形式
int[] nums = {2,5,0,4,1,-10};
System.out.println(Arrays.toString(nums));
/*
* 结果:[2, 5, 0, 4, 1, -10]
*/
Arrays.deepToString(Object[][] arrays)
功能:返回多维数组的字符串形式
int[][] nums = {{1,2},{3,4}};
System.out.println(Arrays.deepToString(nums));
/*
* 结果:[[1, 2], [3, 4]]
*/
二、矩阵建立与基本计算
本篇将模拟两种基本的矩阵计算,一种是对矩阵全元素求和,一种是基本的矩阵加法
1.矩阵元素总量的和
/**
*********************
* Sum the elements of a matrix.
*
* @param paraMatrix The given matrix.
* @return The sum of all its elements.
*********************
*/
public static int matrixElementSum(int[][] paraMatrix) {
int resultSum = 0;
for (int i = 0; i < paraMatrix.length; i++) {
for (int j = 0; j < paraMatrix[0].length; j++) {
resultSum += paraMatrix[i][j];
} // Of for j
} // Of for i
return resultSum;
}// Of matrixElementSum
代码无过多说明,通过双层for循环遍历依次取得每个元素即可。但是额外要注意矩阵的高与宽读取的技巧,与遍历方案。
首先矩阵的高其实就是矩阵的一维部分,一个矩阵在计算机中可以看做是“一维数列”的数组,把这个数组的元素纵向放置就构成了我们视觉可见的一个“矩形”的数字阵列。而这个“一维数列”的数组的长度自然就是这个阵列的纵向长度,也就是高,是把这个数组的元素纵向放置可以排的行数。因此:
paraMatrix.length
就是矩阵的宽,或者说行数。
同理,“一维数列”的数组中的每个元素都是一个一维数列,每个数列的长度就构成了矩阵的长,或者说列数。实际代码中,我们取出“一维数列”的数组的第一个元素,也就是矩阵的第一行,并求这一个行的长度即可:
paraMatrix[0].length
具体遍历的话,基本所有语言的二维存储都是采用行优先的存储,而普遍的遍历都是先行后列的遍历思想,因此这一点不再赘述。
2.矩阵相加
/**
*********************
* Add two matrices. Attention: No error check is provided at this moment.
*
* @param paraMatrix1 The first matirx.
* @param paraMatrix2 The second matrix. It should have the same size as the
* first one's
* @return The addition of these matrices.
*********************
*/
public static int[][] matrixAddition(int[][] paraMatrix1, int[][] paraMatrix2) {
if(paraMatrix1.length!=paraMatrix2.length || paraMatrix1[0].length!=paraMatrix2[0].length) {
System.out.println("Error! Two matrixs must have same height and width! ");
}
int[][] resultMatrix = new int[paraMatrix1.length][paraMatrix1[0].length];
for (int i = 0; i < paraMatrix1.length; i++) {
for (int j = 0; j < paraMatrix1[0].length; j++) {
resultMatrix[i][j] = paraMatrix1[i][j] + paraMatrix2[i][j];
} // Of for j
} // Of for i
return resultMatrix;
}// Of matroxAddition
矩阵相加的话需要符合线性代数中矩阵计算的一个基本要求——即相加的双方矩阵必须是同型的。因此注意对于非法情况的判断。
三、总代码与运行结果
package basic;
import java.util.Arrays;
/**
* This is the seventh code. Names and comments should follow my style strictly.
*
* @author Xingyi Zhang 1328365276@qq.com
*/
public class MatrixAddition {
/**
*********************
* The entrance of the program.
*
* @param args Not used now.
*********************
*/
public static void main(String args[]) {
matrixElementSumTest();
matrixAdditionTest();
}// Of main
/**
*********************
* Sum the elements of a matrix.
*
* @param paraMatrix The given matrix.
* @return The sum of all its elements.
*********************
*/
public static int matrixElementSum(int[][] paraMatrix) {
int resultSum = 0;
for (int i = 0; i < paraMatrix.length; i++) {
for (int j = 0; j < paraMatrix[0].length; j++) {
resultSum += paraMatrix[i][j];
} // Of for j
} // Of for i
return resultSum;
}// Of matrixElementSum
/**
*********************
* Unit test for respective method.
*********************
*/
public static void matrixElementSumTest() {
int[][] tempMatrix = new int[3][4];
for (int i = 0; i < tempMatrix.length; i++) {
for (int j = 0; j < tempMatrix[0].length; j++) {
tempMatrix[i][j] = i * 10 + j;
} // Of for j
} // Of for i
System.out.println("The matrix is: \r\n" + Arrays.deepToString(tempMatrix));
System.out.println("The matrix sum is: " + matrixElementSum(tempMatrix) + "\r\n");
}// Of matrixElementSumTest
/**
*********************
* Add two matrices. Attention: No error check is provided at this moment.
*
* @param paraMatrix1 The first matirx.
* @param paraMatrix2 The second matrix. It should have the same size as the
* first one's
* @return The addition of these matrices.
*********************
*/
public static int[][] matrixAddition(int[][] paraMatrix1, int[][] paraMatrix2) {
if(paraMatrix1.length!=paraMatrix2.length || paraMatrix1[0].length!=paraMatrix2[0].length) {
System.out.println("Error! Two matrixs must have same height and width! ");
}
int[][] resultMatrix = new int[paraMatrix1.length][paraMatrix1[0].length];
for (int i = 0; i < paraMatrix1.length; i++) {
for (int j = 0; j < paraMatrix1[0].length; j++) {
resultMatrix[i][j] = paraMatrix1[i][j] + paraMatrix2[i][j];
} // Of for j
} // Of for i
return resultMatrix;
}// Of matroxAddition
/**
*********************
* Unit test for respective method.
*********************
*/
public static void matrixAdditionTest() {
int[][] tempMatrix = new int[3][4];
for (int i = 0; i < tempMatrix.length; i++) {
for (int j = 0; j < tempMatrix[0].length; j++) {
tempMatrix[i][j] = i * 10 + j;
} // Of for j
} // Of for i
System.out.println("The matrix is: \r\n" + Arrays.deepToString(tempMatrix));
int[][] tempNewMatrix = matrixAddition(tempMatrix, tempMatrix);
System.out.println("The new matrix is: \r\n" + Arrays.deepToString(tempNewMatrix));
}// Of matrixAddtionTest
}// Of class MatrixAddtion
运行结果
一些总结与感慨
java提供了许多的库,而这些库方法能对一些基本的操作进行优化。本篇的矩阵相加并不是很难的一部分,但是却暗示了不同语言的实现思路,不同语言对于数组的声明以及遍历的策略。
例如Java的Arrays库之中的deepToString()方法就让我联想到了Python的print()方法对于各种单一数据类型输出与非单一数据类型数据输出的“大一统”的便利,这样的思路是C,C++,甚至C#中没有的,也难怪有人说python与java有一定相似性。另外其中数组声明中也能看到C#后来学习的影子,可见当年微软抛弃Sun公司自己仿造java创建C#的影子。
另外本文提到的矩阵也是一种非常重要的数据结构,虽然许多语言对于矩阵实现封装库信息很有限(除开matlab这种从矩阵角度出发的编程语言),但是其包含的算法却仍然非常丰富,因此基于基础的二维数组数据模拟复杂的矩阵算法能极大锻炼我们的代码思维与对矩阵之中包含的数学逻辑的理解。
同时,矩阵在计算机视觉中的应用中也扮演着关键作用,其中延伸出来的图像处理算法也在继续为后世服务。当然还有在一系列工程数学上的应用等等。因此关于矩阵的算法与分析也将是计算机学习生活永远绕不开的话题啊。
明天也将继续深入矩阵的其余运算。