Java开发零基础篇:day07 数组高级

简介: 数组高级

 数组拷贝

(1)定义一个方法arraycopy, 从指定源数组中从指定的位置开始复制指定数量的元素到目标数组的指定位置。

拷贝前:

image.gif编辑

拷贝后:

image.gif编辑

代码如下:

public class ArrayUtils { 
    private ArrayUtils() {
        /**
          * 复制数组操作
          *
          * @param src      源数组
          * @param srcPos   源数组中的开始索引位置
          * @param dest     目标数组
          * @param destPos  目标数据中的开始索引位置
          * @param length   要复制的数组长度
          */
        public static void arraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) {
            for (int index = 0; index < length; index++) { 
                dest[destPos + index] = src[srcPos + index];
        }
    }
}

image.gif

测试类:

public class Test01ArrayCopy {
    public static void main(String[] args) {
        int[] a = new int[]{10, 20, 30, 40, 50, 60, 70};
        int[] b = new int[10];
        ArrayUtils.arraycopy(a, 2, b, 4, 3);
        // 测试复制数组后的结果
        for (int i = 0; i < b.length; i++) { 
            System.out.print(b[i] + ",");
        }
    }
}

image.gif

控制台输出:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 30, 40, 50, 0, 0, 0]

image.gif

排序操作

(1)完成对int[] arr = new int[]{2,9,6,7,4,1}数组元素的升序排序操作.

image.gif编辑

冒泡排序原理

对未排序的各元素从头到尾依次比较相邻两个元素的大小关系,如果前一个元素大于后一个元素则交换位置,经过第一轮比较后可以得到最大值,同理第二轮比较后出现第二大值等。

针对int[] arr = new int[]{ 2, 9, 6, 7, 4, 1 }数组元素做排序操作:

该数组有6个元素,只需要5轮比较。

第1轮比较:需要比较5次,比较完出现第一个大值。
第2轮比较:需要比较4次,比较完出现第二大值。
第3轮比较:需要比较3次,比较完出现第三大值。
...
可以看出如有N个元素,则需要N-1轮比较,第M轮需要N-M次比较。

image.gif

交换数组中两个元素的方法

public class ArrayUtils { 
    private ArrayUtils() {
    }
    // 通过索引交换数组索引处值
    public static void swap(int[] arr, int index1, int index2) { 
        int temp = arr[index1];
        arr[index1] = arr[index2]; arr[index2] = temp;
    }
}

image.gif

排序代码:

public class ArrayUtils { 
    private ArrayUtils() {
    }
    public static void swap(int[] arr, int index1, int index2) { 
        int temp = arr[index1];
        arr[index1] = arr[index2]; 
        arr[index2] = temp;
    }
    public static void bubbleSort(int[] arr) {
        //第一轮:
        for (int i = 1; i <= arr.length-1; i++) { 
            if (arr[i - 1] > arr[i]) {
                swap(arr, i - 1, i);
            }
        }
        //第二轮:
        for (int i = 1; i <= arr.length - 2; i++) { 
            if (arr[i - 1] > arr[i]) {
                swap(arr, i - 1, i);
            }
        }
        //第三轮:
        for (int i = 1; i <= arr.length - 3; i++) {
            if (arr[i - 1] > arr[i]) {
                swap(arr, i - 1, i);
            }
        }
        // 第四轮呢?
    }
}

image.gif

寻找规律,优化上述代码:

public static void bubbleSort(int[] arr) {
    for (int times = 1; times <= arr.length - 1; times++) {
        //times表示第几轮比较,值为:1,2,3,4,5
        for (int i = 1; i <= arr.length - times; i++) { 
            if (arr[i - 1] > arr[i]) {
                ArrayUtils.swap(arr, i - 1, i);
            }
        }
    }
}

image.gif

测试:

public class Test02ArraySort {
    public static void main(String[] args) {
        int[] arr = new int[] { 2, 9, 6, 7, 4, 1 }; 
        ArrayUtils.bubbleSort(arr);
        // 测试复制数组后的结果
        for (int i = 0; i < arr.length; i++) { 
            System.out.print(arr[i] + ",");
        }
    }
}

image.gif

       

二分法查找

查找数组元素的算法:

       线性查找:从头找到尾,性能比较低。

       二分法查找(折半查找):前提数组元素是有序的,性能非常优异。

二分法搜索原理

猜数字游戏:

电脑随机生成一个[ 1 , 100 ]之间的整数a,等玩家来猜,猜之后,电脑提示出三种结果:你猜的数偏大,偏小和猜中了。此时为了使用最少次数猜中,玩家必定先猜(1+100)/2的商50,如果此时电脑提示猜的偏小了,那就能推断出该随机数在[ 51 , 100 ]之间,此时再猜(51+100)/2的商75,如果电脑提示猜大了,那么该随机数必在[ 51 , 74 ]之间,那么继续猜(51+74)/2的商,如此每次都可以排除剩下结果一半的可能性,直到猜到为止。

image.gif编辑

代码如下:

public class ArrayUtils { 
    private ArrayUtils() {
    }
    public static int binarySearch(int[] arr, int key) { 
        int low = 0;
        int high = arr.length - 1;
        while (low <= high) {
            int mid = (low + high) / 2; 
            int midVal = arr[mid];
            if (midVal < key) { 
                low = mid + 1;
            } else if (midVal > key) { 
                high = mid - 1;
            } else {
                return mid;
            }
       }
        // 没有找到
        return -1;
    }
}

image.gif

测试类:

public class Test03ArraySearch {
    public static void main(String[] args) {
    int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; 
        int idx = ArrayUtils.binarySearch(arr,8); 
        System.out.println("idx = " + idx);
    }
}

image.gif

操作数组的API-Arrays

类似打印数组元素的这样的工具性的方法,其实SUN公司的攻城狮们早就写好代码了,并封装在了很多工具类中,我们把这种预先定义好的方法,称为API。对于我们而言,最基本的要求就是能调用这 些方法,当然我们对自己有更高的要求,应该知其然,并知其所以然。

Arrays工具类中的方法,一般都是使用static修饰的。

打开JDK帮助文档,搜索Arrays类,进入该类的文档页面,去找toString方法,发现在Arrays类中有多个

toString方法,他们之间属于重载关系,分别用于打印不同类型的数组。

image.gif编辑

如: 查看Arrays类中将int类型数组转换成字符串的toString方法。

image.gif编辑

如果看方法列表看不懂怎么使用,使用鼠标左键点击该方法名称,进入该方法的详细:

image.gif编辑

打印数组元素

API中还有一个专门操作数组的工具类Arrays,该类提供了对数组元素的拷贝、元素搜索、元素排序、打印等功能方法,且该类为不同数据类型的数组都重载了相同功能的方法。

(1)通过调用Arrays类中的toString方法完成打印数组元素的功能。

public class Test01ToString {
    public static void main(String[] args) {
    int[] arr = new int[] { 10, 20, 30, 40, 50, 60, 70 }; 
        String str = Arrays.toString(arr); 
        System.out.println(str);
    }
}

image.gif

拷贝数组元素

Arrays 中提供了数组复制的方法,copyOf(int[] original, int newLength) 复制指定的数组,截取或者用0填充。

System类中提供了数组元素拷贝的方法,并且支持任意类型的数组拷贝,而不仅仅是int类型数组。

public class Test02ArrayCopy {
    public static void main(String[] args) {
        // copyOf
        // 截取场景
        int[] arr = new int[] { 10, 20, 30, 40, 50, 60, 70 };
        // int[] newArr = Arrays.copyOf(arr, 3);
        // 填充场景
        int[] newArr = Arrays.copyOf(arr, 10); 
        System.out.println(Arrays.toString(newArr));
        // System.arraycopy() int[] arr2 = {1,2,3,4};
        int[] newArr2 = new int[10];
        System.arraycopy(arr2,0,newArr2,0,arr2.length);
        System.out.println(Arrays.toString(newArr2));
    }
}

image.gif

数组元素排序

Arrays类中已经提供了数组排序的方法sort,并且是调优之后的,性能非常优异,在开发中只需要我们直接调用该方法即可即可。

public class Test03Sort{
    public static void main(String[] args) {
        int[] arr = new int[] { 2, 9, 6, 7, 4, 1 };
        System.out.println(Arrays.toString(arr));//排序前Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));//排序后
    }
}

image.gif

数组元素二分查找

Arrays类中已经提供了数组元素的二分查找。

public class Test04Search{
    public static void main(String[] args) {
    int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
        int index = Arrays.binarySearch(arr, 8); 
        System.out.println(index);
    }
}

image.gif

数组元素的增删改查操作

假设我现在是某个篮球队的教练,需要安排5个球员上场打球。此时需要模拟上场球员的存储,简 单一点,我们就只存储上场球员的球衣号码。那么此时我需要以下几个操作:

(1)初始一个容量为5的容器,用来存储场上的5个球衣号码。

(2)安排5个球员上场,比如球员号码分别为11、22、33、44、55。

(3) 查询指定索引位置球员的球衣号码是多少,如查询索引位置为2的球衣号码是33。

(4)替换场上索引位置为2的球员,使用333号替换33号。

(5)罚下场上索引位置为2的球员(直接罚下,没有补位)。

(6) 打印**出场上球员的球衣号码,打印风格如 [11,22,33,44,55]。

初始化操作

使用Integer数组来存储场上球员号码,提供了两个构造器,一个用于自定义初始化容量,一个用于使用默认的初始化容量10。

public class PlayerList {
    // 存储场上球员的号码
    private Integer[] players = null;
    // 记录场上球员的数量
    private int size = 0;
    public PlayerList(int capacity){ 
        if(capacity < 0){
            System.out.println("初始容量不能为负数");
            return;
        }
        this.players = new Integer[capacity];
    }
    public PlayerList() { 
        this(0);
    }
}

image.gif

测试类:

public class Test01PlayerList {
    public static void main(String[] args) {
        //初始容量为默认的10
        PlayerList list1 = new PlayerList();
        //自定义初始化容量为5
        PlayerList list2 = new PlayerList(5);
        //自定义初始化容量为20
        PlayerList list3 = new PlayerList(20);
    }
}

image.gif

打印输出操作

public String toString() { 
    if(null == players){
        return "null";
    }
    if(0 == size){ 
        return "[]";
    }
    StringBuilder sb = new StringBuilder(); 
    sb.append("[");
    for(int index = 0;index < size;index++){ 
        sb.append(this.players[index]);
        if(index != size - 1){ 
            sb.append(",");
        }else{
            sb.append("]");
        }
    }
    return sb.toString();
}

image.gif

追加操作

// 向球场上添加一个球员(号码)
public void add(Integer number){ 
    this.players[size] = number;
    // 球员个数增加1
    size++;
}

image.gif

测试类:

public class Test01PlayerList {
    public static void main(String[] args) {
        //初始化容器,设置初始化容量为5 
        PlayerList list = new PlayerList(5); 
        System.out.println(list);
        //向容器中添加5个元素(球员号码) list.add(11);
        list.add(22);
        list.add(33);
        list.add(44);
        list.add(55);
        //打印容器中每一个元素
        ystem.out.println(list);
    }
}

image.gif

因为数组的长度是固定的,此时的players数组只能存储5个元素,如果再多存储一个就报错:数组索引越界。此时就要考虑在保存操作时对数组做扩容操作。

扩容的原理是:

创建一个原数组长度两倍长的新数组

把旧数组中的所有元素拷贝到新数组中

把新数组的引用赋给旧数组变量

保存操作时扩容操作:

// 向球场上添加一个球员(号码)
public void add(Integer number){
    // 检测容器容量是否已满,如果已满,需要拓容。
    if(size == players.length){
        this.players = Arrays.copyOf(this.players, size * 2);
    }
    // ---------------------------
    this.players[size] = number;
    // 球员个数增加1 size++;
}

image.gif

查询操作

(1)查询指定索引位置球员的球衣号码是多少,如查询索引位置为的球衣号码是。其实就是返回数组中,指定索引对应的元素值。

public Integer get(int index) {
    if (index < 0 || index >= size) {
      System.out.println("索引越界"); 
        return null;
    }
    return players[index];
}

image.gif

测试类:

public class Test01PlayerList {
    public static void main(String[] args) { 
        Integer r = list.get(2); 
        System.out.println(r);
    }
}

image.gif

修改操作

(1)替换场上索引位置为2的球员,使用333号替换33号

//替换指定位置的球员号码
public void set(int index, Integer newPlayerNumber) { 
    if (index < 0 || index >= size) {
        System.out.println("索引越界");
        return;
    }
    this.players[index] = newPlayerNumber;
}

image.gif

删除操作

(1)罚下场上索引位置为的球员(直接罚下,没有补位)。删除操作的原理,把后续的元素整体往前挪动一个位置。

//删除指定位置的球员号码
public void remove(int index) {
    if (index < 0 || index >= size) {
        System.out.println("索引越界"); return;
    }
    for (int i = index; i < size - 1; i++) { 
        players[i] = players[i + 1];
    }
    players[size - 1] = null; size--;
}

image.gif

测试类:

public class Test01PlayerList {
    public static void main(String[] args) {
        PlayerList list = new PlayerList(5); 
        list.add(11);
        list.add(22);
        list.add(33);
        list.add(44);
        list.add(55);
        list.remove(2); 
        System.out.println(list);
    }
}

image.gif

以上就是Java入门第七天的全部内容了。

资料文档地址:Java开发零基础篇:day07数组高级.pdf

目录
相关文章
|
4天前
|
人工智能 自然语言处理 Java
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
文章介绍了Spring AI,这是Spring团队开发的新组件,旨在为Java开发者提供易于集成的人工智能API,包括机器学习、自然语言处理和图像识别等功能,并通过实际代码示例展示了如何快速集成和使用这些AI技术。
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
|
6天前
|
存储 前端开发 JavaScript
【前端学java】一篇文章带你精通java 中的数组(10)
【8月更文挑战第10天】一篇文章带你精通java 中的数组
9 3
【前端学java】一篇文章带你精通java 中的数组(10)
|
6天前
|
Java 索引
java中的栈(利用数组实现栈)
这篇文章通过Java代码示例介绍了如何使用数组实现栈操作,包括栈的初始化、入栈、出栈、判断栈满和空以及遍历栈的方法。
java中的栈(利用数组实现栈)
|
8天前
|
前端开发 Oracle Java
【前端学java】java开发的依赖安装与环境配置(1)
【8月更文挑战第8天】java开发的依赖安装与环境配置
26 1
【前端学java】java开发的依赖安装与环境配置(1)
|
1天前
|
数据采集 供应链 JavaScript
分享基于Java开发的Java毕业设计实战项目题目
这篇文章分享了67套基于Java开发的毕业设计实战项目题目,覆盖了互联网、企业管理、电子政务、Java基础项目、ERP系统、校园相关、医疗以及其他细分行业等多个领域,并推荐了使用IDEA、Vue和Springboot的技术栈。
|
1天前
|
分布式计算 Java API
Java 8带来了流处理与函数式编程等新特性,极大提升了开发效率
Java 8带来了流处理与函数式编程等新特性,极大提升了开发效率。流处理采用声明式编程模型,通过filter、map等操作简化数据集处理,提高代码可读性。Lambda表达式支持轻量级函数定义,配合Predicate、Function等接口,使函数式编程无缝融入Java。此外,Optional类及新日期时间API等增强功能,让开发者能更优雅地处理潜在错误,编写出更健壮的应用程序。
6 1
|
11天前
|
Java
Java数组几道练习题
Java数组几道练习题
27 11
|
6天前
|
SQL 存储 Java
完整java开发中JDBC连接数据库代码和步骤
该博客文章详细介绍了使用JDBC连接数据库的完整步骤,包括加载JDBC驱动、提供连接URL、创建数据库连接、执行SQL语句、处理结果以及关闭JDBC对象的过程,并提供了相应的示例代码。
|
7天前
|
安全 前端开发 Java
Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例
在Web安全上下文中,源(Origin)是指一个URL的协议、域名和端口号的组合。这三个部分共同定义了资源的来源,浏览器会根据这些信息来判断两个资源是否属于同一源。例如,https://www.example.com:443和http://www.example.com虽然域名相同,但由于协议和端口号不同,它们被视为不同的源。同源(Same-Origin)是指两个URL的协议、域名和端口号完全相同。只有当这些条件都满足时,浏览器才认为这两个资源来自同一源,从而允许它们之间的交互操作。
Web端系统开发解决跨域问题——以Java SpringBoot框架配置Cors为例
|
1天前
|
人工智能 网络协议 Java
23.12月中旬 上海寻序人工智能科技-上海嘉定-Java开发实习生-薪资150-230/d 面经
关于上海寻序人工智能科技有限公司Java开发实习生岗位的面试经验分享,涵盖了技术问题如对象存储MinIO、ArrayList扩容、Object类方法、hashCode和equals方法、处理哈希冲突、JVM垃圾回收器、GC算法、网络协议、邮件协议、HTTP请求方法、Linux和Docker命令、Dockerfile制作等。
3 0