Java 数据结构篇-模拟实现动态数组

🔥博客主页: 小扳_-CSDN博客
❤感谢大家点赞👍收藏⭐评论✍
   

 

 

本篇目录

        1.0 动态数组说明

        2.0 模拟实现动态数组的核心方法

        2.1 动态数组-插入与扩容

        2.2 动态数组-获取元素

        2.3 动态数组-修改元素

        2.4 动态数组-删除元素

        2.5 动态数组-遍历元素(重点)

        2.5.1 使用 forEach 循环元素

        2.5.2 使用迭代器循环元素

        2.5.3  使用 Stream 流来循环元素

        2.6 补充关于拷贝的方法

        3.0 对以上代码进行汇总整理升级


        1.0 动态数组说明

        在 Java 中,动态数组可以使用 ArrayList 类来实现。ArrayList 类是 Java 集合框架中的一个类,它可以动态地增加或减少元素的大小。与普通数组相比,ArrayList 具有动态增长和缩小的能力,可以根据需要自动调整数组的大小。

        

        2.0 模拟实现动态数组的核心方法

        该动态数组中的成员变量分别为:Object[] myArrayList 数组int size 元素个数int defaultSize 默认大小。在 ArrayList 类中,在未添加元素之前为空,因此,Object[] myArrayList = {}size 默认为0;当第一个元素添加进来的时候,defaultSize 默认为10

具体代码如下:

public class ImitateArray<E> implements Iterable<E>{
    private int defaultSize = 10;
    private Object[] myArraylist= {};
    private int size = 0;

    //无参构造器
    public ImitateArray() {
    }

        2.1 动态数组-插入与扩容

        add(element): 向动态数组的末尾添加一个元素。如果数组已满,则需要扩容。

具体代码如下:

    public boolean add(E e){
        if (size == 0){
            myArraylist = new Object[defaultSize];
        }
        //先判断是否需要扩容
        if (isExpansion()) {
            expansion();
          }
        myArraylist[size] = e;
        size++;
        return true;
    }


    //是否需要扩容
    private boolean isExpansion(){
        return size >= defaultSize;
    }
    //数组扩容
    private boolean expansion(){
        defaultSize = (int) (defaultSize * 1.5);
        Object[] temp = new Object[(int) (defaultSize)];
        //for (int i = 0; i < myArraylist.length; i++) {
        //    temp[i] = myArraylist[i];
        //}
        System.arraycopy(myArraylist,0,temp,0,size);
        myArraylist = temp;
        System.out.println("扩容成功!");
        return true;
    }


        对以上代码进行分析:

        在添加元素前,

        第一,先判断是否首元素插入,如果是首元素,需要创建数组对象,默认大小为10

        第二,判断 size == defaultSize,如果是,就需要扩容了,数组扩容大小为原来的1.5倍defaultSize += defaultSize >>> 1,扩容成功之后,需要将原数组中的元素拷贝回到新数组中,可以用的方法为 System.arraycopy(myArraylist,0,temp,0,size);

        第三,添加完元素之后,需要进行 size++

        2.2 动态数组-获取元素

        get(index): 获取指定索引处的元素。

具体代码如下:

        

    public E get(int index){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        return (E)myArraylist[index];
    }

        对以上代码进行分析:

        获取元素之前,先要判断是否越界访问数组。

        2.3 动态数组-修改元素

        set(index, element): 修改指定索引处的元素。

具体代码如下:

    public E set(int index,E e){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        E temp = (E) myArraylist[index];
        myArraylist[index] = e;
        return temp;
    }

        同理,在修改元素之前先要判断是否为越界访问。

        2.4 动态数组-删除元素

        remove(index): 删除指定索引处的元素。如果删除后数组的空余空间过多,则需要缩容。

具体代码如下:

    //根据索引删除数据
    public boolean remove(int index){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        if (index == size - 1){
            myArraylist[index] = null;
        }else {
            //1,2,3,4,5
            //0,1,2,3,4
            for (int i = index; i < size; i++) {
                myArraylist[i] = myArraylist[i + 1];
            }
        }
        size--;
        return true;
    }

        对以上代码进行分析:
        先判断是否越界访问,再判断若要删除的元素为最后一个,则直接 null,接着 size--。其他情况需要缩容,myArraylist[i] = myArraylist[i + 1];

        2.5 动态数组-遍历元素(重点)

        介绍三种方式来遍历元素:

        第一种,实现使用 forEach 循环元素

        第二种,实现使用迭代器循环元素

        第三种,实现使用 Stream 流来循环元素

        2.5.1 使用 forEach 循环元素

具体代码如下:

public interface Consumer <E>{
    void accept(E e);
}
    //实现forEach
    public void forEach(Consumer<E> consumer) {
        Object[] temp = new Object[size];
        for (int i = 0; i < size; i++) {
            temp[i] = myArraylist[i];
        }
        for (Object o : temp) {
            consumer.accept((E)o);
        }

    }
        imitateArray.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.print(integer+" ");
            }
        });

        对以上代码进行分析:

        先实现一个接口,然后用 fori 循环,将有效元素都拷贝到新的数组中,接着用 foreach 循环来对每个元素进行操作,具体由用户决定了。 

        2.5.2 使用迭代器循环元素

具体代码如下:

首先需要实现 Iterable 接口;

    //重写迭代器
    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int i = 0;
            @Override
            public boolean hasNext() {
                return i < size;
            }

            @Override
            public E next() {
                return (E) myArraylist[i++];
            }
        };
    }
for (Integer integer : imitateArray) {
    System.out.print(integer+" ");
}

        补充;大部分的集合都实现该迭代器,因此不是所有类都具有迭代器的。

        2.5.3  使用 Stream 流来循环元素

具体代码如下:

    //用流进行遍历
    public Stream stream(){
        //第一种比较晦涩难懂
        //return Arrays.stream(Arrays.copyOf(myArraylist,size)).map(e->(E) e);
        
        //第二种比较好理解一点
        Stream<Object> stream1 = Stream.of(Arrays.copyOf(myArraylist,size));
        return stream1.map(e->(E) e);
    }
      imitateArray.stream().forEach(s-> System.out.print(s+" "));
    

        重点注意:在 stream 方法中,使用 Stream.of((E) myArraylist) 来创建一个流,但是这样会将整个数组对象作为一个元素添加到流中,而不是将数组中的元素逐个添加到流中。

        因此,使用 map 方法来对流中的每个元素进行操作。在这里使用 lambda 表达式 (e -> (E) e) 来将每个元素 (e) 强制转换为 E 类型。这样就可以将流中的元素类型转换为 E 类型。

         2.6 补充关于拷贝的方法

        第一个,System.arraycopy(myArraylist,0,temp,0,size),用于一个或者两个数组,从 myArraylist 数组从第 0 个索引拷贝到 temp 数组中从第 0 个索引开始,一共要拷贝 size 个元素。

        第二个,Arrays.copyof(int[] original, int newlength),用于从原来的数组拷贝到新数组的个数为 newlength 个。

        第三个,Arrays.copyOfRange(int[] original, int from, int to) ,将指定数组的指定范围复制到新数组中。 

        3.0 对以上代码进行汇总整理升级

public interface Consumer <E>{
    void accept(E e);
}

模拟实现 ArrayList 的代码:

import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;

public class ImitateArray<E> implements Iterable<E>{
    private int defaultSize = 10;
    private Object[] myArraylist= {};
    private int size = 0;

    public ImitateArray() {
    }
    //添加元素
    public boolean add(E e){
        if (size == 0){
            myArraylist = new Object[defaultSize];
        }
        //先判断是否需要扩容
        if (isExpansion()) {
            expansion();
          }
        myArraylist[size] = e;
        size++;
        return true;
    }

    //根据索引来查询数据
    public E get(int index){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        return (E)myArraylist[index];
    }

    //根据索引删除数据
    public boolean remove(int index){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        if (index == size - 1){
            myArraylist[index] = null;
        }else {
            //1,2,3,4,5
            //0,1,2,3,4
/*            for (int i = index; i < size; i++) {
                myArraylist[i] = myArraylist[i + 1];
            }*/
            System.arraycopy(myArraylist,index + 1,myArraylist,index,size - index -1);
        }
        size--;
        return true;
    }

    //根据索引来更改数据
    public E set(int index,E e){
        if (index >= size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        E temp = (E) myArraylist[index];
        myArraylist[index] = e;
        return temp;
    }

    //数组长度
    public int size(){
        return size;
    }

    //实现forEach
    public void forEach(Consumer<E> consumer) {
        Object[] temp = new Object[size];
        for (int i = 0; i < size; i++) {
            temp[i] = myArraylist[i];
        }
        for (Object o : temp) {
            consumer.accept((E)o);
        }

    }

    //根据索引插入元素
    public boolean insert(int index,E e){
        if (index > size || index < 0){
            throw new RuntimeException("越界!!!");
        }
        if (index == size){
            //直接调用 add 方法
            add(e);
        }
        if (isExpansion()){
            expansion();
        }
        //Object[] temp = new Object[defaultSize];
/*        for (int i = 0; i < index; i++) {
            temp[i] = myArraylist[i];
        }
        temp[index] = e;
        for (int i = index; i < size ; i++) {
            temp[i+1] = myArraylist[i];
        }*/
        System.arraycopy(myArraylist,index ,myArraylist,index + 1,size - index);
        myArraylist[index] = e;
        //myArraylist = temp;
        size++;
        return true;
    }

    //是否需要扩容
    private boolean isExpansion(){
        return size >= defaultSize;
    }
    //数组扩容
    private boolean expansion(){
        defaultSize = (int) (defaultSize * 1.5);
        Object[] temp = new Object[(int) (defaultSize)];
/*        for (int i = 0; i < myArraylist.length; i++) {
            temp[i] = myArraylist[i];
        }*/
        System.arraycopy(myArraylist,0,temp,0,size);
        myArraylist = temp;
        System.out.println("扩容成功!");
        return true;
    }
    //重写 toString 方法
    @Override
    public String toString() {
        Object[] temp = new Object[size];
        for (int i = 0; i < size; i++) {
            temp[i] = myArraylist[i];
        }
        return "ImitateArray{" +
                "myArraylist=" + Arrays.toString(temp) +
                '}';
    }

    //重写迭代器
    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int i = 0;
            @Override
            public boolean hasNext() {
                return i < size;
            }

            @Override
            public E next() {
                return (E) myArraylist[i++];
            }
        };
    }

    //用流进行遍历
    public Stream stream(){
        //第一种比较晦涩难懂
        //return Arrays.stream(Arrays.copyOf(myArraylist,size)).map(e->(E) e);

        //第二种比较好理解一点
        Stream<Object> stream1 = Stream.of(Arrays.copyOf(myArraylist,size));
        return stream1.map(e->(E) e);
    }
}

以下为测试类: 

public class Text {
    public static void main(String[] args)  {
        ImitateArray<Integer> imitateArray = new ImitateArray<>();
        imitateArray.add(1);
        imitateArray.add(2);
        imitateArray.add(3);
        imitateArray.add(4);
        imitateArray.add(5);
        imitateArray.add(6);
        imitateArray.add(7);
        imitateArray.add(8);
        imitateArray.add(9);
        imitateArray.add(10);
        imitateArray.add(11);
        imitateArray.add(12);
        System.out.println(imitateArray);

        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);
        imitateArray.insert(11,11);

/*        ArrayList<Integer> list = new ArrayList<>();
        list.forEach(new java.util.function.Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {

            }
        });*/

        imitateArray.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.print(integer+" ");
            }
        });
        System.out.println();

        for (Integer integer : imitateArray) {
            System.out.print(integer+" ");
        }

        System.out.println();
        imitateArray.stream().forEach(s-> System.out.print(s+" "));
    }
}

                

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/115112.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Flutter 04 按钮Button和事件处理、弹框Dialog、Toast

一、按钮组件 1、按钮类型&#xff1a; 2、按钮实现效果&#xff1a; import package:flutter/material.dart;void main() {runApp(const MyApp()); }class MyApp extends StatelessWidget {const MyApp({Key? key}) : super(key: key);overrideWidget build(BuildContext co…

Langchain-Chatchat项目:4.2-P-Tuning v2使用的数据集

本文主要介绍P-tuning-v2论文中的5种任务&#xff0c;分别为Glue任务、NER任务、QA任务、SRL任务、SuperGlue任务&#xff0c;重点介绍了下每种任务使用的数据集。 一.Glue任务   GLUE&#xff08;General Language Understanding Evaluation&#xff09;是纽约大学、华盛顿…

Spring IOC详解

文章目录 目录 文章目录 前言 一 . SpringFramework介绍 1.1 Spring和SpringFramework概念 1.2 SpringFramework主要功能模块 二 . Spring IOC容器和核心概念 2.1 组件和组件管理 2.1.1 什么是组件? 2.1.2 组件管理 2.2 Spring IOC容器和容器实现 2.2.1 Sprign IO…

nodejs+springboot+elementui+python的Sd球鞋销售平台的设计与实现-毕业设计

此网站系统的开发方式和信息管理方式&#xff0c;借鉴前人设计的信息和研发。以网站商品信息为主&#xff0c;购物商品为核心功能来进行设计和研发&#xff0c;把网站信息和技术整合&#xff0c;开发出一套Sd球鞋销售平台。用目前现有的新技术进行系统开发&#xff0c;提供后台…

Oracle注入(基础篇)

先了解Oracle一些内容 Oracle做联合注入的注意事项(附带示例) 联合查询的字段数必须和前面的查询语句字段数一致 select id,username,password from admin union select 1,admin from dual (X) 联合查询的字段类型也必须和前面的查询语句字段类型一致 select id,username,pas…

OpenAI最新官方GPT最佳实践指南,一文讲清ChatGPT的Prompt玩法

原文&#xff1a;Sina Visitor System OpenAI的官网发表万字GPT最佳实践指南&#xff0c;讲清Prompt提示词的原则和策略&#xff0c;这里是总结和全文翻译 原创图像&#xff0c;AI辅助生成 OpenAI的官网上刚刚发表一篇万字的GPT最佳实践指南&#xff0c;这份指南把写好Promp…

路由器基础(七):NAT原理与配置

一、NAT 配置 华为路由器配置NAT 的方式有很多种&#xff0c;考试中可能考到的基本配置方 式主要有EasyIP和通过NAT地址池的方式。图22-7-1是一个典型的通过EasyIP进行NAT的示意图&#xff0c;其中Router出接口GE0/0/1的IP地址为200.100.1.2/24,接口E0/0/1的IP地址为192.168.0.…

MySQL - 库的操作

目录 1.库的操作1.1创建数据库1.2创建数据库案例 2.字符集和校验规则3.操纵数据库4.备份和恢复5.查看连接情况 1.库的操作 1.1创建数据库 语法&#xff1a; CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] create_specifica…

递归与快速算法

借鉴&#xff1a; 4分钟彻底掌握递归算法、斐波那契数列、快速排序&#xff0c;不再怕面试&#xff01;_哔哩哔哩_bilibili 可直接观看借鉴里的视频 快速算法

QT学习之QT概述

1.1 什么是QT&#xff1f; Qt是一个跨平台的C图形用户界面应用程序框架。 QT特点&#xff1a; 跨平台&#xff0c;几乎支持所有的平台接口简单&#xff0c;容易上手&#xff0c;学习QT框架对学习其他框架有参考意义。一定程度上简化了内存回收机制开发效率高&#xff0c;能够…

Nacos全面知识 ----微服务 SpringCloud

快速入门 分级存储模型 修改集群配置 Nacos设置负载均衡策略 集群优先 权重优先 Nacos热更新配置 Nacos添加配置信息 微服务配置拉取 热更新:推荐使用第二种方法进行热部署 ConfigurationProperties(prefix "pattern") 是 Spring Boot 中用于自动配置属性的注解。它…

MATLAB 绘制 SISO 和 MIMO 线性系统的时间和频率响应图

系列文章目录 文章目录 系列文章目录前言一、时间响应二、频率响应三、极点/零点图和根节点四、响应特性五、分析 MIMO 系统六、系统比较七、修改时间轴或频率轴数值如果觉得内容不错&#xff0c;请点赞、收藏、关注 前言 本例演示如何绘制 SISO 和 MIMO 线性系统的时间和频率…

直播电商大变局:店播时代终于来了!

店播时代终于来了。 直播在2023年双十一的亮点&#xff0c;也是焦点。今年双十一&#xff0c;舆论场的注意力都集中在了几大平台的头部主播身上&#xff0c;却少有人注意店播的表现——根据淘宝直播官方数据&#xff0c;10月31日淘宝直播上有29个直播间开局即破亿&#xff0c;…

【MATLAB源码-第67期】基于麻雀搜索算法(SSA)的无人机三维地图路径规划,输出最短路径和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 ​麻雀搜索算法&#xff08;Sparrow Search Algorithm, SSA&#xff09;是一种新颖的元启发式优化算法&#xff0c;它受到麻雀社会行为的启发。这种算法通过模拟麻雀的食物搜索行为和逃避天敌的策略来解决优化问题。SSA通过模…

Anaconda安装与配置

1.打开Anaconda官网&#xff0c;选择对应版本,下载到对应目录即可 或者进入: Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2.双击打开.exe文件&#xff0c;然后点击next ; 3.点击agree 4.点击just me,然后next; 5.在Choose Install L…

Linux 安装node并全局可用

前言 基于&#xff1a;操作系统 CentOS 7.6 工具&#xff1a;Xshell7、Xftp7 1.下载 根目录创建一个 node 文件夹并进入 mkdir /node && cd /node下载压缩包 wget https://nodejs.org/download/release/v16.18.0/node-v16.18.0-linux-x64.tar.gz2.解压并重命名 …

oracle 重启步骤及踩坑经验

oracle 重启步骤及踩坑经验 标准重启步骤 切换到oracle用户 su - oracle关闭监听 lsnrctl stop杀掉oracle有关进程 ps -ef|grep $ORACLE_SID|grep -v ora_|grep LOCALNO|awk {print $2}|xargs kill -9#查询pid ps -ef|grep $ORACLE_SID|grep -v ora_|grep LOCALNO|awk {p…

第 5 章 主窗口及对话框

5.1 主窗口区域划分 QMainWindow是Qt框架带来的一个预定义的主窗口类。所谓主窗口&#xff0c;就是一个普通意义上的应用程序最顶层的窗口。例如对于浏览器而言&#xff0c;主窗口就是这个浏览器窗口。回想一下&#xff0c;经典的主窗口通常由一个标题栏、一个菜单栏、若干工具…

【Linux】常见的Linux命令

目录 一、与目录有关的操作 二、与文件有关的操作 三、针对目录的操作 三、在linux上搭建环境 一、与目录有关的操作 1.ls 显示目录内容列表 ls / 这里的 / 表示根目录&#xff0c;相当于windows中的此电脑&#xff0c;linux中没有盘符。 ls -l / 显示详细信息 可以…

基于Taro + React 实现微信小程序半圆滑块组件、半圆进度条、弧形进度条、半圆滑行轨道(附源码)

效果&#xff1a; 功能点&#xff1a; 1、四个档位 2、可点击加减切换档位 3、可以点击区域切换档位 4、可以滑动切换档位 目的&#xff1a; 给大家提供一些实现思路&#xff0c;找了一圈&#xff0c;一些文章基本不能直接用&#xff0c;错漏百出&#xff0c;代码还藏着掖…