我们来继续上一篇博客中对Java中数组的解读,
我们先来回顾一下
感兴趣的小伙伴可以进去看看哦数组(一)
数组(一)中我们解读到了数组的应用场景
那么这篇博客主要针对数组的一些练习和运用以及二维数组进行解析
使用这个我们以后打印数组就会更加方便一点。
Java中提供了java.util.Arrays包,其中包含了一些操作数组的常用方法。
这里给大家列举几个常用的方法
1、二叉搜索算法
使用二叉搜索算法搜索指定值的指定数组的范围。在进行此呼叫之前,范围必须按照sort(int[], int, int)方法进行排序。如果没有排序,结果是未定义的。如果范围包含具有指定值的多个元素,则不能保证将找到哪个元素。
2、复制数组内容(下面我还会再提到)
复制指定的数组,用零截取或填充(如有必要),以便复制具有指定的长度。对于原始数组和副本都有效的所有索引,两个数组将包含相同的值。对于在副本中而不是原件有效的任何索引,副本将包含0 。当且仅当指定长度大于原始数组的长度时,这些索引才会存在。
3、数组深度比较
//如果数组包含其他数组作为元素,则字符串表示包含其内容等等。
//此方法用于将多维数组转换为字符串。
//字符串表示由数组元素的列表组成,括在方括号( "[]" )中。
//相邻的元素由字符", " (逗号后跟一个空格)分隔开。
//元件由String.valueOf(Object)转换为字符串,除非它们本身阵列。
//如果一个元素e是一个基本类型的阵列,它通过调用的Arrays.toString(e)适当重载转换为字符串作为。
//如果元素e是引用类型的数组,则通过递归调用此方法将其转换为字符串。
//为了避免无限递归,如果指定的数组包含自身作为元素,或者通过一个或多个数组级别包含对其自身的间接引用,则将自引用转换为字符串"[...]" 。
//例如,仅包含对其自身的引用的数组将被呈现为"[[...]]" 。
//如果指定数组是null此方法返回"null"。
4、️按照数组顺序排序
按照数字顺序排列数组的指定范围。要排序的范围从索引fromIndex (包括)扩展到索引toIndex 。如果fromIndex == toIndex ,要排序的范围是空的。
a - 要排序的数组
fromIndex - 要排序的第一个元素的索引(包括)
toIndex - 最后一个要排序的元素的索引
4、equals比较和fill填充
这里用代码来解释
public static void main_ArrayEqualsAndFill(String[] args) {
int[] array1 = {1,2,3,4,5};
int[] array2 = {1,2,3,4,5};
boolean equal = Arrays.equals(array1,array2);
System.out.println(equal);
System.out.println("==============");
int[] array = new int[10];
System.out.println("填充之前的数组"+Arrays.toString(array));
// 结果都是0
Arrays.fill(array,1);
System.out.println("填充之后的数组"+Arrays.toString(array));
// 结果都是1
Arrays.fill(array,4,10,29);
// 从[4,10)填充29
}
其他的我就不多做介绍了,小伙伴们可以自己去了解一下~
这里我们其实就可以发现了,重载函数真的很常见!
这里我们用代码来进行讲解
运行结果
这里newArr和arr引用的是同一个数组,因此newArr修改空间中内容之后,arr也可以看到修改的结果
运行结果
使用Arrays中copyOf方法完成对数组的拷贝:
copyOf方法在进行数组拷贝时,创建了一个新的数组
arr和newArr引用的不是同一个数组
因为arr修改其引用数组中内容时,对newArr没有任何影响
运行结果
newArr2:[3,4]
这里有一点要注意的是,从2下标拷贝到4下标,都是左闭右开的,不要搞错[2,4)
这个copyOfRange方法看起来很方便呀!让我们瞧瞧得用CTRL+左键来管中窥豹一下源码吧
啊,就这么短短几行!而且一眼看过去就可以清楚每行代码的用途,简单干练。
果然还是那句话,最好的代码不是生涩难懂的,而是大家都能看得明白的!
这里我简单画个图来帮大家理解一下
我们在这里要注意的是:数组当中存储的是基本类型数据的时候,不论怎么拷贝基本都不会出现什么问题,但如果存储的是引用数据类型,拷贝的时候就需要考虑深浅拷贝的问题,Arrays中也有相关deepCopyOf等方法,这里待我将数据结构学习透彻再为大家讲解
除了用Java提供的方法,我们当然也可以运用自己写的拷贝数组的方法
运行结果
// 求平均值
public static double avg(int[] array) {
int sum = 0;
for (int i = 0;i<array.length;i++){
sum = sum +array[i];
}
return sum*1.0/array.length;
// 不能 return sum/array.length
}
public static int search(int[] array,int key){
for(int i=0;i<array.length;i++){
if(array[i]==key){
return i;
}
}
// 如果代码走到这里,说明推出了for循环
return -1;//因为数组没有负数下标
}
public static void main_search(String[] args) {
int[] array = {1,2,3,4,5};
int index = search(array,4);
if(index == -1){
System.out.println("没有你要找的关键字!");
}else {
System.out.println("找到了你要的关键字,下标是:"+ index);
}
}
针对有序数组我们可以进行更加快速的二分查找,一定要注意,是有序!也就是说二分查找的前提是数组是排好序的,千万不要因为这个小细节犯错哦。
而有序数组分为升序和降序,1234为升序,4321为降序
以升序数组为例,二分查找的思路是先取中间位置的元素,然后使用待查找元素与数组中间元素进行比较:
// 二分查找,前提是查找的数组有序
public static int binarySearch(int[] array,int key){
int left = 0;
int right = array.length-1;
while (left<=right){
int mid = (left + right) /2;
if (array[mid]<key){
left = mid + 1;
}else if(array[mid]==key){
return mid;
}else {
right = mid -1;
}
}
// 代码走到这里说明left已经大于right了,所以返回-1
return -1;//数组没有-1
}
可以看到,针对一个很多元素的数组查找,二分查找的效率极其高,随着数组元素个数越多,那么二分的优势就越大
(字好丑小伙伴们谅解一下~)
我们用代码来演示一下
这里的sort会自动为我们排序,但它是默认升序的,那么我们再来见识一下源码
!这又是一个方法,哼哼我再点进去看看
…好家伙,4162行代码,见识不过来了,等有空我再为大家去庖丁解牛(鸽王发言)
public static void bubbleSort(int[] array) {
//[0----len-1)i代表趟数
for (int i = 0;i<array.length-1;i++){
boolean flg = false;
//j<4在这里可以不减i 减i说明是进行了优化
for(int j=0;j<array.length-1-i;j++){
if (array[j] > array[j+1]) {
int tmp = array[j];
array[j] = array[j+1];
array[j+1] = tmp;
flg = true;
}
}
if (flg == false) {
// 这里是判断上一次有没有进行交换,flg有没有变成true
break;
}
}
// 这里还可以进一步优化,我们可以进一步添加检查,
// 检查是否发生了简化,如果没有,说明有序了,就不需要进行第三趟,第四趟...
}
冒泡排序相对Arrays提供的sort性能还是欠佳,所以还是多多利用Arrays提供的方法咯
我们给定一个数组,然后将里面的元素逆序排列
思路如下:
设定两个下标,分别指向第一个和最后一个元素,减缓两个位置的元素
然后让前一个下标自增,后一个下标自减,循环继续即可
public static void reverse(int[] arr) {
int left = 0;
int right = arr.length-1;
int tmp = 0;
while (left<right){
tmp = arr[left];
arr[right] = tmp;
left++;
right--;
}
很简单,就不细说啦
基本语法
数据类型[][] 数组名称 = new 数据类型 [行数][列数] {初始化数据};
介绍几种初始化方式
import java.util.ArrayList;
public class TestDemo{
public static void main(String args[]) {
int[][]a1= {{1,2},{3,4},{5,6,7}};
for(int i=0;i<a1.length;i++) {
System.out.print(a1[i].length+" ");
for(int j=0;j<a1[i].length;j++)
System.out.print(a1[i][j]+" ");
System.out.println();
}
System.out.println();
int[][]a2=new int[2][3];
for(int i=0;i<a2.length;i++) {
System.out.print(a2[i].length+" ");
for(int j=0;j<a2[i].length;j++)
System.out.print(a2[i][j]+" ");
System.out.println();
}
System.out.println();
int[][]a3=new int[2][];
for(int i=0;i<a3.length;i++) {
a3[i]=new int[3];
System.out.print(a3[i].length+" ");
for(int j=0;j<a3[i].length;j++)
System.out.print(a3[i][j]+" ");
System.out.println();
}
System.out.println();
ArrayList<Integer> a4[]=new ArrayList[3];
for(int i=0;i<a4.length;i++) {
a4[i]=new ArrayList();
a4[i].add(1);
for(int j:a4[i])
System.out.print(j+" ");
System.out.println();
}
}
}
输出
2 1 2
2 3 4
3 5 6 7
3 0 0 0
3 0 0 0
3 0 0 0
3 0 0 0
1
1
1
二维数组的用法和一维数组并没有明显的差别,所以不在赘述,除了要注意的是不规则数组的情况,
这里我给出一段代码,来帮助大家理解
public static void main_3(String[] args) {
int[] arr = {1,2,3,4,5,6};
String newArr = Arrays.toString(arr);
System.out.println(newArr);
}
public static void main_2(String[] args) {
// int[][] array = {{1,2},{4,5,6}};是可以这样定义的
int[][] array2=new int[2][];//这里编译器只知道这里有两行,还没给出列
array2[0] = new int[2];
array2[1] = new int[4];
// 这叫不规则数组
for (int i = 0;i<array2.length;i++){//代表我们的行
for (int j =0;j<array2[i].length;j++){//代表我们的列
System.out.println(array2[i][j]);
}
}
// 这里没有array2[0] = new int[2];
// array2[1] = new int[4];
// 会显示空指针异常,
// PS:这里区别于C语言,不能再使用array+1来表示数组地址了
}
public static void main_1(String[] args){
// 二维数组不能这么写 int[][] array = {1,2,3,4,5,6};
int[][] array = {{1,2,3},{4,5,6}};
int[][] array2 = new int [][]{{1,2,3},{4,5,6}};
for (int i = 0;i<2;i++){//代表我们的行
for (int j =0;j<3;j++){//代表我们的列
System.out.println(array[i][j]);
}
}
// 优化一下
for (int i = 0;i<array.length;i++){//代表我们的行
for (int j =0;j<array[i].length;j++){//代表我们的列
System.out.println(array[i][j]);
}
}
System.out.println("使用for-each来进行打印");
for (int[] tmp:array){
for(int x:tmp){
System.out.println(x+" ");
}
}
System.out.println("使用toString进行打印");
System.out.println(Arrays.deepToString(array));
//
}
以下是我在学习数组中用到的代码,如果有需要的小伙伴自取~
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args){
int[] arr = {1,2,3,10,5,6};
System.out.println(find(arr,10));
}
public static int find(int[] arr, int data){
for (int i=0;i<arr.length;i++){
if (arr[i] == data){
return i;
}
}
return -1;//
}
public static void main_average(String[] args) {
int[] arr = {1,2,3,4,5,6};
System.out.println(average(arr));
}
public static double average(int[] arr) {
int sum = 0;
for (int x: arr){
sum += x;
}
return (double) sum/(double) arr.length;
}//执行结果为3.5
public static void main_4(String[] args) {
int[] array = {1,2,3,4,5,6};
int[] array2= new int[6];
System.out.println("未拷贝前:" + Arrays.toString(array2));
array2 = copyOf(array);
System.out.println("拷贝了之后:"+Arrays.toString(array2));
}
public static int[] copyOf(int[] arr){
int[] ret =new int[arr.length];
for (int i = 0;i<arr.length;i++){
ret[i] = arr[i];
}
return ret;
}
public static void copyOf2(int[] arr){
//这里newArr和arr引用的是同一个数组
//因此newArr修改空间中内容之后,arr也可以看到修改的结果
int[] arr2 = {1,2,3,4,5,6};
int[] newArr = arr2;
newArr[0] = 10;
System.out.println("newArr: "+Arrays.toString(arr2));
arr[0] = 1;
newArr = Arrays.copyOf(arr,arr.length);
System.out.println("newArr:" + Arrays.toString(newArr));
// 使用Arrays中copyOf方法完成对数组的拷贝:
//copyOf方法在进行数组拷贝时,创建了一个新的数组
//arr和newArr引用的不是同一个数组
//因为arr修改其引用数组中内容时,对newArr没有任何影响
arr[0] = 10;
System.out.println("arr:" + Arrays.toString(arr));
System.out.println("newArr: "+Arrays.toString(newArr));
//拷贝某个范围
int[] newArr2 = Arrays.copyOfRange(arr,2,4);
System.out.println("newArr2: "+ Arrays.toString(newArr2));
}
public static void main_3(String[] args) {
int[] arr = {1,2,3,4,5,6};
String newArr = Arrays.toString(arr);
System.out.println(newArr);
}
public static void main_2(String[] args) {
// int[][] array = {{1,2},{4,5,6}};是可以这样定义的
int[][] array2=new int[2][];//这里编译器只知道这里有两行,还没给出列
array2[0] = new int[2];
array2[1] = new int[4];
// 这叫不规则数组
for (int i = 0;i<array2.length;i++){//代表我们的行
for (int j =0;j<array2[i].length;j++){//代表我们的列
System.out.println(array2[i][j]);
}
}
// 这里没有array2[0] = new int[2];
// array2[1] = new int[4];
// 会显示空指针异常,
// PS:这里区别于C语言,不能再使用array+1来表示数组地址了
}
public static void main_1(String[] args){
// 二维数组不能这么写 int[][] array = {1,2,3,4,5,6};
int[][] array = {{1,2,3},{4,5,6}};
int[][] array2 = new int [][]{{1,2,3},{4,5,6}};
for (int i = 0;i<2;i++){//代表我们的行
for (int j =0;j<3;j++){//代表我们的列
System.out.println(array[i][j]);
}
}
// 优化一下
for (int i = 0;i<array.length;i++){//代表我们的行
for (int j =0;j<array[i].length;j++){//代表我们的列
System.out.println(array[i][j]);
}
}
System.out.println("使用for-each来进行打印");
for (int[] tmp:array){
for(int x:tmp){
System.out.println(x+" ");
}
}
System.out.println("使用toString进行打印");
System.out.println(Arrays.deepToString(array));
//
}
public static void reverse(int[] arr) {
int left = 0;
int right = arr.length-1;
int tmp = 0;
while (left<right){
tmp = arr[left];
arr[right] = tmp;
left++;
right--;
}
}
public static void bubbleSort(int[] array) {
//[0----len-1)i代表趟数
for (int i = 0;i<array.length-1;i++){
boolean flg = false;
//j<4在这里可以不减i 减i说明是进行了优化
for(int j=0;j<array.length-1-i;j++){
if (array[j] > array[j+1]) {
int tmp = array[j];
array[j] = array[j+1];
array[j+1] = tmp;
flg = true;
}
}
if (flg == false) {
// 这里是判断上一次有没有进行交换,flg有没有变成true
break;
}
}
// 这里还可以进一步优化,我们可以进一步添加检查,
// 检查是否发生了简化,如果没有,说明有序了,就不需要进行第三趟,第四趟...
}
public static void main_ArrayEqualsAndFill(String[] args) {
int[] array1 = {1,2,3,4,5};
int[] array2 = {1,2,3,4,5};
boolean equal = Arrays.equals(array1,array2);
System.out.println(equal);
System.out.println("==============");
int[] array = new int[10];
System.out.println("填充之前的数组"+Arrays.toString(array));
// 结果都是0
Arrays.fill(array,1);
System.out.println("填充之后的数组"+Arrays.toString(array));
// 结果都是1
Arrays.fill(array,4,10,29);
// 从[4,10)填充29
}
public static void main_Array(String[] args) {
int[] array = {1,2,3,14,5};
System.out.println("排序之前的数组:"+Arrays.toString(array));
Arrays.sort(array);//默认升序
System.out.println("排完序之后的数组"+Arrays.toString(array));
//index:下标,索引
int index = Arrays.binarySearch(array,14);
if (index == -1){
System.out.println("没有");
}else {
System.out.println("下标为"+index);
}
}
// 二分查找,前提是查找的数组有序
public static int binarySearch(int[] array,int key){
int left = 0;
int right = array.length-1;
while (left<=right){
int mid = (left + right) /2;
if (array[mid]<key){
left = mid + 1;
}else if(array[mid]==key){
return mid;
}else {
right = mid -1;
}
}
// 代码走到这里说明left已经大于right了,所以返回-1
return -1;//数组没有-1
}
public static int search(int[] array,int key){
for(int i=0;i<array.length;i++){
if(array[i]==key){
return i;
}
}
// 如果代码走到这里,说明推出了for循环
return -1;//因为数组没有负数下标
}
public static void main_search(String[] args) {
int[] array = {1,2,3,4,5};
int index = search(array,4);
if(index == -1){
System.out.println("没有你要找的关键字!");
}else {
System.out.println("找到了你要的关键字,下标是:"+ index);
}
}
// 求平均值
public static double avg(int[] array) {
int sum = 0;
for (int i = 0;i<array.length;i++){
sum = sum +array[i];
}
return sum*1.0/array.length;
// 不能 return sum/array.length
}
public static void main1(String[] args) {
int[] array = {1,2,3,4,5};
int[] ret = {1,2,3};
ret =Arrays.copyOfRange(array,1,3);
System.out.println(Arrays.toString(ret));
// 这里输出为[2,3]
// 因为从1下标拷贝到3下标,这里都是左闭右开的[1,3)
}
}
到这里,数组就完结啦,后期如果有需要补充的我会另外添加,希望大佬们帮我指正~
感谢阅读!