数据结构-ArrayLIst-一起探索顺序表的底层实现

news2025/1/16 11:02:27

各位看官早安午安晚安呀

如果您觉得这篇文章对您有帮助的话

欢迎您一键三连,小编尽全力做到更好
欢迎您分享给更多人哦

大家好,我们今天来学习java数据结构的第一章ArrayList(顺序表)

1.ArrayList的概念

那小伙伴就要问了线性表到底是什么呢?
线性表 linear list n 个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列...(我们后续都会进行讲解)
线性表首先是一个序列,也就是说,元素之间是有顺序的,如果元素存在多个,那么第一个元素无前驱。最后一个元素无后驱。其他每个元素都必须有一个前驱和后驱
例如:
usedSize这个变量是非常重要的,我们的增删查改都要用到

1.2ArrayList的模拟实现

import java.util.Arrays;

public class MyArrayList {

    private int []elem;//用来存放数据
    private int usedSize;//非常重要,代表当前顺序表当中的有效数据个数

    private static final int DEFAULT_SIZE = 2;

    public MyArrayList() {
        this.elem = new int[DEFAULT_SIZE];
    }
    public MyArrayList(int initCapacity){
        this.elem = new int[initCapacity];
    }

    // 新增元素,默认在数组最后新增
    public void add(int data) {
        if(elem.length == usedSize){
            elem = Arrays.copyOf(elem,elem.length*2);
        }
        elem[usedSize] = data;
        this.usedSize++;//一定不要忘记加
    }
    // 在 pos 位置新增元素
    public void add(int pos, int data) {//只要带pos的都要进行检查
        if(checkPos(pos) ==false ){
            return;
        }
            if (elem.length == usedSize) {
            elem = Arrays.copyOf(elem, elem.length * 2);
        }
            //下面这种写法就错误了,导致pos后面的值都是pos位置的值
        /*for (int i = pos; i < usedSize -1; i++) {
            elem[i+1] = elem[i];
        }*/
        //应该从后往前
        for (int i = usedSize-1 ; i >= pos; i--) {
            elem[i+1] = elem[i];
        }
        elem[pos] = data;
        usedSize++;
    }

    /*public void delete(int pos){
        if(checkPos(pos) == false)
        if(this.usedSize == 0){
            System.out.println("数组里面没有元素了");
            return;
        }
        for (int i = 0; i < usedSize - 1; i++) {
            elem[i] = elem[i+1];
        }
    }
*/

    // 判定是否包含某个元素
    public boolean contains(int toFind) {//啥意思
        for (int i = 0; i < usedSize; i++) {
            if(elem[i] == toFind ) //这里是int类型,所以你能够直接比较,其他类型的话,要重写equals方法
                return true;
        }
        return false;
    }

    // 查找某个元素对应的位置
    public int indexOf(int toFind) {
        for (int i = 0; i < usedSize; i++) {
            if(elem[i] == toFind)
            return i;
        }
        System.out.println("没有你要找的值");
        return -1;
    }

    public boolean checkPos(int pos){
        if( pos < 0 || pos >= usedSize){
            System.out.println("下标错误");
            return false;
        }
        return true;
    }
    // 获取 pos 位置的元素
    public int get(int pos) {

        if(checkPos(pos) == false){
            return -1;
        }
        return elem[pos];
    }

    // 给 pos 位置的元素设为 value
    public void set(int pos, int value) {
        if(checkPos(pos) == false){
            return;
        }
        elem[pos] = value;
    }

    //删除第一次出现的关键字key
    public void remove(int data) {
        int index = this.indexOf(data);
        if(index == -1){
            System.out.println("没有这个数据");
            return;
        }
        for (int i = data; i < usedSize - 1; i++) {
            elem[i] = elem[i+1];
        }
       //如果是引用类型的话: elem[index] = null;
        this.usedSize--;

    }

    // 获取顺序表长度
    public int size() {
        return this.usedSize;
    }

    // 清空顺序表
    public void clear() {
        this.usedSize = 0;
        //但是如果是引用类型的话
/*
        for (int i = 0; i < usedSize; i++) {
            elem[i] = null;
            记得全部置为空
            引用类型的话,删除也要置为null
        }
*/
    }

    // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
    public void display() {
        for (int i = 0; i < usedSize; i++) {
            System.out.print(this.elem[i] + " ");
        }
    }
}

目前我们自己实现了顺序表这种结构,以后用到的时候,Java已经为我们提供好了

ArrayList(就是一个普通的类实现了List接口)

(自己看一下方法)(ArrayLIst里面的方法,底层方法)(我们可以看出来ArrsyList底层的数组我们在实例化对象时也是默认长度为我们的常量值,有效元素个数非常重要,我们增加删除元素等方法都要用的)

2:构造方法

我们要了解一个类首先要了解他的构造方法

ArrayList<E>中的E就表示列表中存储的元素的类型

ArrayList

2.1:构造方法一,三

       ArrayList<Integer> list = new ArrayList<>();   这种能用的方法更多
       List<Integer> list = new ArrayList<>();    一般我们用这一种,向上转型,动态绑定的等等,你俩用哪个主要看自己业务场景
       ArrayList<Integer> list = new ArrayList<>(15)

我们可以看到默认数组长度是10,前面源码图解上有

2.2:构造方法二

然后我把list1指定的类型换成Integer就解决问题了!

大家也可以看到我明明对于list3只add了一次但是,打印出来的值却把list1数组里面的内容也拷贝过来了(拷贝在外面构造方法那一步就完成了)

2.3:ArrayList常见操作

public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(1,4);
        System.out.println(list);//到这里是【1,4,2,3】

        list.remove(1);//这两个老是搞混,这个是删除1小标的值
        list.remove(new Integer(1));//要删除1这个元素的值一定要用这种方法,因为这个参数是Object类型的
        System.out.println(list);//到这里是【2,3】

        // list.get(2);//这里会报一个数组越界异常,就是用来和UsedSize比较

        list.add(99);
        list.add(100);
        list.add(101);
        boolean isFalse = list.contains(new Integer(100));//这里最好用Integer类型的
        System.out.println(isFalse);//true

        List<Integer> list1 = list.subList(1,4);//左闭右开
        System.out.println(list1);

        list.set(1,200);
        System.out.println(list);
        System.out.println(list1);
        //list1得到的是从list数组里面的引用,只要改变其中一个元素的值,另一个也会改变

        list.clear();
        System.out.println(list);
        //全部清除
    }

2.4:ArrayList的三种遍历

ArrayList 可以使用三方方式遍历: for 循环 + 下标、 foreach 、使用迭代器
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
// 使用下标+for遍历
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
System.out.println();
// 借助foreach遍历
for (Integer integer : list) {
System.out.print(integer + " ");
}
System.out.println();

//迭代器
Iterator<Integer> it = list.listIterator();
//ListIterator<Integer> it = list.listIterator();也可以
//ListIterator是Iterator的子类
while(it.hasNext()){
System.out.print(it.next() + " ");
}
System.out.println();
}
注意:
1. ArrayList 最长使用的遍历方式是: for 循环 + 下标 以及 foreach
2. 迭代器是设计模式的一种,后续博客我会继续讲解

2.5:ArrayList的扩容机制的缺陷

ArrayList是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容。以下是ArrayList源码中扩容方式
总结
1. 检测是否真正需要扩容,如果是调用 grow 准备扩容
2. 预估需要库容的大小
初步预估按照 1.5 倍大小扩容 ,如果用户所需大小超过预估1.5 倍大小,则按照用户所需大小扩容
真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
3. 使用 copyOf 进行扩容

3:杨辉三角

力扣杨辉三角

实现:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
    public static void main(String[] args) {
        int num = 5;
        List<Integer> row = new ArrayList<>();
        List<List<Integer>> ret = new ArrayList<>();
        row.add(1);
        ret.add(row);
        for (int i = 1; i < num; i++) {
            List<Integer> curRow1 = new ArrayList<>();
            curRow1.add(1);//每行的第一个元素都是1

            List<Integer> previousRow = ret.get(i - 1);

            for (int j = 1; j < i; j++) {
                Integer x = previousRow.get(j) + previousRow.get(j - 1);
                curRow1.add(x);

            }
            curRow1.add(1);//每行的最后一个元素也都是1

            ret.add(curRow1);//把这一行的数组加进去
        }
        for (List<Integer>list:ret   //遍历数组
             ) {
            System.out.println(list);
        }
        System.out.println("============================");
        Iterator<List <Integer>> it = ret.listIterator();//使用迭代器遍历数组
//ListIterator<Integer> it = list.listIterator();也可以
//ListIterator是Iterator的子类
        while(it.hasNext()){
            System.out.print(it.next() + " ");
            System.out.println();
        }

    }
    }

上述就是数据结构-ArrayLIst-数组的深入包装 的全部内容了,能看到这里相信您一定对小编的文章有了一定的认可,数据结构的出现让我们对于数据的组织的利用有了更加方便的使用~~

有什么问题欢迎各位大佬指出
欢迎各位大佬评论区留言修正

您的支持就是我最大的动力​​​!!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity2017 控制.abc格式的三维动画播放

首先需要导入插件Alembic&#xff0c;否则导入abc动画&#xff0c;Unity是不会识别的。 Unity2017版本及以下直接从我这儿下载&#xff1a;https://download.csdn.net/download/qq_41603955/90272382 高版本Unity&#xff0c;请移步AssetStore商店搜找。 导入abc之后&#x…

docker虚拟机平台未启用问题

在终端中输入如下代码&#xff0c;重启电脑即可 Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform 对于Docker Desktop - Unexpected WSL error问题 参考链接 解决WSL2与docker冲突问题

软件设计大致步骤

由于近期在做软件架构设计&#xff0c;这里总结下大致的设计流程 软件设计流程 1 首先要先写系统架构图&#xff0c;将该功能在整个系统的位置以及和大致的内部模块划分 2 然后写内部的结构图&#xff0c;讲内部的各个子系统&#xff0c;模块&#xff0c;组件之间的关系和调用…

EasyLine(v2.0)自制光谱、曲线处理软件

前言&#xff1a;因为这次更新对软件的整体变动较大&#xff0c;所以就没有取版本v1.1&#xff0c;而是直接使用v2.0版本。然后上一版的讲解也不是很清楚&#xff0c;这次也做重点讲解一下。 自制光谱、曲线处理软件-EasyLine 软件的安装软件的使用总体介绍文件格式处理的使用 …

赛灵思(Xilinx)公司Artix-7系列FPGA

苦难从不值得歌颂&#xff0c;在苦难中萃取的坚韧才值得珍视&#xff1b; 痛苦同样不必美化&#xff0c;从痛苦中开掘出希望才是壮举。 没有人是绝对意义的主角&#xff0c; 但每个人又都是自己生活剧本里的英雄。滑雪&#xff0c;是姿态优雅的“贴地飞行”&#xff0c;也有着成…

晨辉面试抽签和评分管理系统之八:随机编排考生的面试批次(以教师资格考试面试为例)

晨辉面试抽签和评分管理系统&#xff08;下载地址:www.chenhuisoft.cn&#xff09;是公务员招录面试、教师资格考试面试、企业招录面试等各类面试通用的考生编排、考生入场抽签、候考室倒计时管理、面试考官抽签、面试评分记录和成绩核算的面试全流程信息化管理软件。提供了考生…

LeetCode热题100(三十四) —— 23.合并K个升序链表

LeetCode热题100&#xff08;三十四&#xff09; —— 23.合并K个升序链表 题目描述代码实现思路一&#xff1a;选择排序(199ms)思路二&#xff1a;归并排序(2ms) 思路解析 你好&#xff0c;我是杨十一&#xff0c;一名热爱健身的程序员在Coding的征程中&#xff0c;不断探索与…

深入理解 ECMAScript 2024 新特性:字符串 isWellFormed 方法

ECMAScript 2024 引入了一个新的字符串实例方法&#xff1a;String.prototype.isWellFormed。这一新增功能是为了帮助开发者更容易地验证字符串是否为有效的 Unicode 文本。本文将详细介绍这一方法的使用场景、实现原理及其在实际应用中的价值。 String.prototype.isWellFormed…

Springboot和Es整合

说明&#xff1a;本文章主要是简单整合和简单增删改查。 1.pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi…

阀井可燃气体监测仪,开启地下管网安全新篇章-旭华智能

在城市的脉络中&#xff0c;地下管网犹如隐秘的动脉&#xff0c;支撑着现代生活的运转。而在这庞大网络的关键节点上&#xff0c;阀井扮演着不可或缺的角色。然而&#xff0c;由于其密闭性和复杂性&#xff0c;阀井内部一旦发生可燃气体泄漏&#xff0c;将对公共安全构成严重威…

C#中通道(Channels)的应用之(生产者-消费者模式)

一.生产者-消费者模式概述 生产者-消费者模式是一种经典的设计模式&#xff0c;它将数据的生成&#xff08;生产者&#xff09;和处理&#xff08;消费者&#xff09;分离到不同的模块或线程中。这种模式的核心在于一个共享的缓冲区&#xff0c;生产者将数据放入缓冲区&#x…

4.寻找两个正序数组的中位数--力扣

给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 算法的时间复杂度应该为 O(log (mn)) 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,3], nums2 [2] 输出&#xff1a;2.00000 解释&…

2Spark Core

2Spark Core 1.RDD 详解1) 为什么要有 RDD?2) RDD 是什么?3) RDD 主要属性 2.RDD-API1) RDD 的创建方式2) RDD 的算子分类3) Transformation 转换算子4) Action 动作算子 3. RDD 的持久化/缓存4. RDD 容错机制 Checkpoint5. RDD 依赖关系1) 宽窄依赖2) 为什么要设计宽窄依赖 …

面试题刷题

i 或 i 基础几个9&#xff08;评价系统的指标&#xff09; Arrays.aslist 的bug 方法做了重写 这样就能使用了 list的迭代器 不能使用list.remove方法。需要使用迭代器的remove方法 正确操作 Hashcode hashcode是object对象的方法 是一个native方法 hashcode冲突案例和hashcod…

编译pytorch——cuda-toolkit-nvcc

链接 https://blog.csdn.net/wjinjie/article/details/108997692https://docs.nvidia.com/cuda/cuda-installation-guide-linux/#switching-between-driver-module-flavorshttps://forums.developer.nvidia.com/t/can-not-load-nvidia-drivers-on-ubuntu-22-10/239750https://…

Linux网络_套接字_UDP网络_TCP网络

一.UDP网络 1.socket()创建套接字 #include<sys/socket.h> int socket(int domain, int type, int protocol);domain (地址族): AF_INET网络 AF_UNIX本地 AF_INET&#xff1a;IPv4 地址族&#xff0c;适用于 IPv4 协议。用于网络通信AF_INET6&#xff1a;IPv6 地址族&a…

【Go】Go Gorm 详解

1. 概念 Gorm 官网&#xff1a;https://gorm.io/zh_CN/docs/ Gorm&#xff1a;The fantastic ORM library for Golang aims to be developer friendly&#xff0c;这是官网的介绍&#xff0c;简单来说 Gorm 就是一款高性能的 Golang ORM 库&#xff0c;便于开发人员提高效率 那…

51单片机 AT24C02(I2C总线)

存储器 随机存储 RAM 只读存储 ROM AT24C02芯片 是一种可以实现掉电不丢失的存储器&#xff0c;可用于保存单片机运行时想要永久保存的数据信息 存储材质&#xff1a;E2PROM 通讯接口&#xff1a;I2C总线 容量&#xff1a;256字节 I2C总线 一种通用的数据总线 两根通信线…

再见IT!

再见IT 学了三年半前端&#xff0c;今天可能真的要和我最爱的前端说拜拜了&#xff01;没办法大局为重&#xff01; 在这个AI乱飞和短视频风口的时代&#xff0c;只能说当下学习任何一个技术远比2020年学习起来要简单的多。往后技术的发展无疑是飞速的&#xff0c;智能的&…

【开源免费】基于Vue和SpringBoot的人口老龄化社区服务与管理平台(附论文)

本文项目编号 T 140 &#xff0c;文末自助获取源码 \color{red}{T140&#xff0c;文末自助获取源码} T140&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…