Java 之数组问题

数组

数组:相同类型数据的集合,内存是连续的

1.创建数组

int[ ] array = {1,2,3,4};
静态初始化,创建array数组,存放1,2,3,4

int[ ] array = new int[ ] {1,2,3,4};
动态初始化,new 一个array数组,"[ ]"中长度不能给定

int[ ] array = new int[10];
动态创建array数组,长度为10,未存放数据,默认值为0

2.数组的访问

1.通过下标索引访问数组,例:array[i], i表示下标、位置
2.使用array.length获取数组长度,"."操作是成员访问操作符
3.下标访问操作不能超过有效范围[0,length - 1],若超出有效范围,会出现下标越界异常

遍历数组的方法:
1.使用for循环遍历数组

//通过访问下标来遍历数组,数组名为array

for(int i= 0;i<array.length;i++){ 
      System.out.print(array[i]+"  ");
}

2.使用for each 遍历数组

数组名为array
for(int i : array) {                                                              
     System.out.print(i + " ");
}

数组遍历时for循环和for each 的区别:for循环中可以获取到数组的下标,而for each中不能。

3.以字符串的形式打印数组
使用Arrays.toString(array)

System.out.println(Arrays.toString(array));

Arrays:java当中数组操作工具类

3.数组作为方法的参数

3.1数组可作为函数的形参或者实参
  • 参数传递内置类型时,修改形参的值,并不引起实参值的改变
  • 参数传数组类型时,在函数内部修改数组内容,函数外部也发生改变,此时数组名是一个"引用",当传参时,按照引用传参。

什么是引用?
引用相当于一个“别名”,可以理解为一个指针
创建一个引用相当于创建了一个很小的变量,变量中保存了一个整数,整数表示内存中的一个地址。
所谓的“引用”本质上存了一个地址,java将数组设定为引用类型,后续进行数组参数传参时,只是将数组的地址传入到函数形参中,避免对整个数组的拷贝。

  • 数组也可以作为返回值
3.2 JVM内存区域划分

JVM包括以下几个部分:
在这里插入图片描述
1.Java虚拟机栈
存储局部变量表,int[ ] array这样的存储地址的引用等。
2.本地方法栈
native修饰的方法叫本地方法,其特点是底层由C/C++代码进行实现,Java只需调用即可,速度快。
3.程序计数器
存放下一条执行的指令地址
4.堆
new 在堆上开辟内存空间
5.方法区
用于存储已被虚拟机加载的类信息、常量、静态变量、方法编译出的字节码等
常量池:一般存放字符串常量,即双引号引起来的数据

  • 在JDK1.7之前,常量池存放在方法区;在JDK1.7之后,存放在堆上
    每一个线程都会包含:程序计数器,Java虚拟机栈,本地方法栈

4.数组的拷贝方式

4.1使用for循环拷贝数组

public class Test {
    public static int[] copyArray(int[] array1,int[] array2 ) {  
          for(int i=0;i<array1.length;i++){  
                array2[i] = array1[i]; 
           } 
          return array2;     
     }
     public static void main(String[] args){ 
          int[] array1 = {1,2,3,4,5}; 
          int[] array2 = new int[array1.length];  
          int[] array=copyArray(array1,array2);                                          System.out.println(Arrays.toString(array));             
     }
}
4.2使用 Arrays.copyOf( );

这种方法会返回新的对象,底层调用的是"System.arraycopy( )"
3.使用 System.arraycopy( );
这个方法有5个参数:源数组,源数组开始位置,目标数组,目标数组开始位置,拷贝长度

  • 这是一个native 方法,底层由C/C++实现,速度较快
4.3使用 clone( );

定义方法:数组名.clone( );
会返回新的对象

  • 以上4种数组拷贝方式:对于内置/简单类型来说,均是深拷贝;对于引用类型,均为浅拷贝
  • 浅拷贝:当拷贝完成之后,复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化
  • 深拷贝:对象及值复制过来,两个对象修改其中任意的值另一个值不会改变

5.数组的使用

5.1找数组的最大值
public class Test {
    public static int maxNum(int[] array) {
            int a= array[0];
            for(int i =1;i < array.length;i++){
                if(a < array[i]) {
                     a = array[i];
                }
            }
            return a;
        }
        public static void main(String[] args) {
            int[] array1 = {1,2,3,4,5};
            System.out.println (maxNum(array1));
        }
}
5.2找数组的最小值
public class Test {
    public static int minNum(int[] array) {
            int a= array[0];
            for(int i =1;i < array.length;i++){
                if(a > array[i]) {
                     a = array[i];
                }
            }
            return a;
        }
        public static void main(String[] args) {
            int[] array1 = {1,2,3,4,5};
            System.out.println (minNum(array1));
        }
}
5.3求数组的平均数
public class Test {
      public static double avg(int[] array){
            int sum=0;
            for(int i=0;i<array.length;i++){
                 sum += array[i];
            }
            return (double)sum/array.length;
        }

        public static void main(String[] args) {
            int[] array1 ={1,2,3,4,5};
            System.out.println(avg(array1));
        }
  }
5.4数组的逆置

public class Test {
     public static void reverse(int[] array) {
            int i =0;
            int j =array.length-1;
            while(i<j){
                int tmp=array[i];
                array[i]=array[j];
                array[j]=tmp;
                i++;
                j--;
            }
        }
        public static void main(String[] args) {
            int[] array1={1,2,3,4,5};
            reverse(array1);
            System.out.println(Arrays.toString(array1));
        }
 }
5.5将偶数放到奇数前面
public class Test {
    public static void func(int[] array) {
            int i = 0;
            int j = array.length-1;
            while (i != j) {
                while (i < j && array[i] % 2 == 0) {
                    i++;
                }//在前面碰到奇数 停止
                while (i < j && array[j] % 2 != 0) {
                    j--;
                }//在后面碰到偶数  停止
                //交换的前提:
                if(i != j) {
                    int tmp = array[i];
                    array[i] = array[j];
                    array[j] = tmp;
                }
            }
        }

        public static void main(String[] args) {
            int[] array1={1,2,3,4,5};
            func(array1);
            System.out.println(Arrays.toString(array1));
        }
}
5.6冒泡排序

给定一个数组,让其升序或降序排列
若按升序排列:每次对相邻的两个元素进行比较,若前者大于后者则进行交换,如此一趟下来最后一趟的就是最大元素,重复以上的步骤,除了已经确定的元素。

5.6.1.若使用for循环实现

分析可知
数组中有n个元素;需要进行n-1趟冒泡排序;
第一趟需要比较n-1次
第二趟需要比较n-2次

外层for循环控制需要冒泡排序的趟数;
内层for循环控制每次需要进行比较的次数;

public class Test {
    public static void bubbleSort(int[] array) {
        for(int i=0;i<array.length-1;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;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] array1={5,4,2,3,1};
        bubbleSort(array1);
        System.out.print(Arrays.toString(array1));
    }
}

但是这个代码不高效,若给定的数组已按顺序排列,则代码还是会继续执行,冒泡排序的次数和每次比较的趟数还是不会少。

5.6.2.设置标志,判断是否发生交换

为提高效率,我们可以判断每一趟比较完成后,是否有元素发生交换,没有发生交换则说明序列有序,不再进行比较!

public class Test {
     public static void bubbleSort(int[] array) {
            boolean flg = false;
            //趟数
            for (int i = 0; i < array.length-1; i++) {
                flg = false;
                //每一趟的次数
                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) {
                    break;
                }
        }
     public static void main(String[] args) {  
         int[] array1={5,4,2,3,1}; 
         bubbleSort(array1);    
         System.out.print(Arrays.toString(array1));
    }
}
5.6.3.使用Array.sort(数组名);

该方法的底层是一个快速排序,将数组元素从小到大排列。
使用时直接调用即可

public class Test {
    public static void main(String[] args) {
        int[] array ={1,4,3,2,5};
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));
    }
}
5.7 使用二分查找来查找指定元素

二分查找(Binary Search)也叫作折半查找。
二分查找有两个要求:一个是数列有序,另一个是数列使用顺序存储结构(比如数组)。

5.7.1 普通二分查找

以升序数列为例:
首先比较数列中间位置元素与指定元素的大小 ;
若中间位置的元素小于指定元素,则继续在后半部分的数列中进行二分查找;若中间位置的元素大于指定元素,则在数列的前半部分进行比较;
如果相等,则找到了元素的位置。
每次比较的数列长度都会是之前数列的一半,直到找到相等元素的位置或者没有找到指定元素。

public class Test {
    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) {
                return mid;
            } else if (array[mid] < key) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] array1={1,2,3,4,5};
        System.out.println(binarySearch(array1,5));
    }
}

该代码的执行结果返回的是指定元素的位置,即数组下标

5.7.1 使用Arrays.binarySearch();

该方法中有4个参数:数组名,起始下标,终止下标,指定元素
该方法的返回的是指定元素的位置,下标

  • 查找的范围: [起始下标,终止下标)
    包括起始下标,但不包括终止下标。
 public class Test {
    public static void main(String[] args) {
        int[] array1={1,2,3,4,5};
        System.out.println(Arrays.binarySearch(array1,3,6,5));
    }
}
5.7.2使用递归的方法实现二分查找
public class Test {
    public static int binarySearch(int[] array,int left,int right,int key) {
        if (left > right) {
            return -1;
        }
        int mid = (left + right) / 2;
        if (array[mid] == key) {
            return mid;
        } else if (array[mid] > key) {
            right = mid - 1;
            return binarySearch(array, left, right, key);
        } else {
            left = mid + 1;
            return binarySearch(array, left, right, key);
        }
    }

    public static void main(String[] args) {
        int[] array1={1,2,3,4,5};
        System.out.println(binarySearch(array1,0,4,6));
    }
}

与之前的方法相同,该方法的返回的是指定元素的位置,下标

6. 二维数组

6.1 定义方式

规则数组定义方式:

  • int[ ][ ] array={{1,2,3},{4,5,6},{7,8,9}};
  • int[ ][ ] array = new int[ ][ ]{{1,2,3}{4,5,6}};
  • int[ ][ ] array = new int[3][4];
    不规则数组定义方式:
  • int[ ][ ] array={{1,2},{4,5,6},{7,8,9}};;
  • int[ ][ ] array = new int[3][ ];
    array[0] = new int[2];
    array[1] = new int[3];
    array[2] = new int[4];
6.2访问二维数组

array.length 二维数组的行
array[i].length 二维数组的列
通过使用双层for循环来遍历数组:

public class Test {
    public static void main(String[] args){
        int[][] array={{1,2,3},{4,5,6},{7,8,9}};
        for(int i=0;i<array.length;i++){
            for(int j=0;j<array[i].length;j++){
                System.out.print(array[i][j]+"  ");
            }
        }
    }
}
6.2二维数组的内存模型

以 int[ ][ ] array={{1,2,3},{4,5,6},{7,8,9}}; 为例说明二维数组的内存模型:
数组名array,“0,1,2”代表该二维数组有3行,行下标下对应每行数组存储的起始位置。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值