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

目录
相关文章
|
1月前
|
Java API Maven
如何使用Java开发抖音API接口?
在数字化时代,社交媒体平台如抖音成为生活的重要部分。本文详细介绍了如何用Java开发抖音API接口,从创建开发者账号、申请API权限、准备开发环境,到编写代码、测试运行及注意事项,全面覆盖了整个开发流程。
104 10
|
28天前
|
监控 Java API
如何使用Java语言快速开发一套智慧工地系统
使用Java开发智慧工地系统,采用Spring Cloud微服务架构和前后端分离设计,结合MySQL、MongoDB数据库及RESTful API,集成人脸识别、视频监控、设备与环境监测等功能模块,运用Spark/Flink处理大数据,ECharts/AntV G2实现数据可视化,确保系统安全与性能,采用敏捷开发模式,提供详尽文档与用户培训,支持云部署与容器化管理,快速构建高效、灵活的智慧工地解决方案。
|
18天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
37 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
5天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
47 13
|
10天前
|
算法 Java API
如何使用Java开发获得淘宝商品描述API接口?
本文详细介绍如何使用Java开发调用淘宝商品描述API接口,涵盖从注册淘宝开放平台账号、阅读平台规则、创建应用并申请接口权限,到安装开发工具、配置开发环境、获取访问令牌,以及具体的Java代码实现和注意事项。通过遵循这些步骤,开发者可以高效地获取商品详情、描述及图片等信息,为项目和业务增添价值。
43 10
|
3天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
38 2
|
13天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
29天前
|
开发框架 Java 关系型数据库
Java哪个框架适合开发API接口?
在快速发展的软件开发领域,API接口连接了不同的系统和服务。Java作为成熟的编程语言,其生态系统中出现了许多API开发框架。Magic-API因其独特优势和强大功能,成为Java开发者优选的API开发框架。本文将从核心优势、实际应用价值及未来展望等方面,深入探讨Magic-API为何值得选择。
40 2
|
1月前
|
监控 前端开发 Java
【技术开发】接口管理平台要用什么技术栈?推荐:Java+Vue3+Docker+MySQL
该文档介绍了基于Java后端和Vue3前端构建的管理系统的技术栈及功能模块,涵盖管理后台的访问、登录、首页概览、API接口管理、接口权限设置、接口监控、计费管理、账号管理、应用管理、数据库配置、站点配置及管理员个人设置等内容,并提供了访问地址及操作指南。
|
29天前
|
IDE Java 编译器
开发 Java 程序一定要安装 JDK 吗
开发Java程序通常需要安装JDK(Java Development Kit),因为它包含了编译、运行和调试Java程序所需的各种工具和环境。不过,某些集成开发环境(IDE)可能内置了JDK,或可使用在线Java编辑器,无需单独安装。
62 1