ArrayList与顺序表(一)

news2024/10/3 2:21:57

目录

1.线性表

 2.顺序表

2.1接口的实现

3.ArrayList的简介

4.ArrayList使用

4.1ArrayList的构造

4.2ArrayList常见的操作

4.3ArrayList的遍历

4.4ArrayList的扩容机制

 5.模拟实现一个ArrayList

 


1.线性表

线性表:是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表,链表,栈,队列...

线性表在逻辑上线性结构,也就是说连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上储存时,通常以数组和链式结构的形式储存。

 2.顺序表

顺序表是用一段物理地址连续的储存单元一次储存数据元素的线性结构,一般情况下采用数组储存。在数组上完成数据的增删查改。

2.1接口的实现

//顺序表接口的实现
class MyArrayList {
    private int[] array;
    private int size;
    
    //默认的构造方法
    public MyArrayList() {   }
    //将顺序表的底层容量设置成initcapacity
    public MyArrayList(int initcapacity) {  }
    //新增元素,默认在数组的最后新增
    public void add(int data) {   }
    //在pos位置新增元素
    public void add(int pos, int data) {   }
    //判断是否包含某个元素
    public boolean contains(int toFind) { return true; }
    //寻找某个元素对应的下标
    public int indexOf(int toFind) { return -1; }
    //获取pos位置的元素
    public int get(int pos) { return -1; }
    //给pos位置的元素设为value
    public void set(int pos, int value) { }
    //删除第一次出现的关键字key
    public void remove(int toRemove) {  }
    //获取顺序表长度
    public int size() { return 0; }
    //清空顺序表
    public void clear() {  }
    
    
    //为了方便测试,我们打印顺序表
    public void display() {  }
}

3.ArrayList的简介

在集合框架中,ArrayList是一个普通类,实现了List接口。

【说明】

  1. ArrayList是以泛型方式实现的,使用时必须要先实例化;
  2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问;
  3. ArrayList实现了Cloneable接口,表示ArrayList是可以clone的;
  4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的;
  5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList;
  6. ArrayList的底层是一段连续的空间,可以进行动态扩容,是一个动态类型的顺序表。

4.ArrayList使用

4.1ArrayList的构造

方法解释
ArrayList()无参构造
ArrayList(Collection<? extends E> c)利用其他的Collection构造ArrayList
ArrayList(int initialCapacity)指定顺序表初始容量
//ArrayList的使用
public class Test {
    public static void main(String[] args) {
        //无参构造
        List<Integer> list1 = new ArrayList<>();
        //构造一个10容量的列表
        List<Integer> list2 = new ArrayList<>(10);
        //构造一个和list2中元素一致
        ArrayList<Integer> list3 = new ArrayList<>(list2);
    }
}

4.2ArrayList常见的操作

ArrayList提供了很多的方法,但是常用的方法是有限的,我们接下来进行演示。

//ArrayList常用的方法
public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        //在数组的末尾进行添加元素
        System.out.println("=========在数组的末尾进行添加元素=========");
        list.add("javaSE");
        list.add("javaWeb");
        list.add("javaEE");
        list.add("JVM");
        list.add("末尾");
        System.out.println(list);

        //获取list中有效的元素个数
        System.out.println("============获取list有效的元素个数=============");
        System.out.println(list.size());

        System.out.println("============获取和设置1位置的元素===============");
        System.out.println(list.get(1));
        list.set(1, "1位置修改");
        System.out.println(list.get(1));

        System.out.println("============在某位置插入指定元素================");
        list.add(1,"插入1位置");
        System.out.println(list);

        System.out.println("=============删除指定位置元素==================");
        list.remove("插入1位置");
        System.out.println(list);
        list.remove(1);
        System.out.println(list);

        System.out.println("=============检测是否包含某一元素===============");
        System.out.println(list.contains("java"));

        System.out.println("=============在数组中查找某一元素,并返回其下标====");
        System.out.println(list.indexOf("javaEE"));
        System.out.println(list.lastIndexOf("javaEE"));

        System.out.println("=============使用list中[0,2)之间的元素构成一个新的数组,但是其实是共用的一个数组=========");
        List<String> ret = list.subList(0,2);
        System.out.println(ret);

        System.out.println("=============清空数组=========================");
        list.clear();
        System.out.println(list.size());

    }
}

4.3ArrayList的遍历

ArrayList可以使用三种方式来遍历: for循环+下表、foreach、使用迭代器

//遍历
public class Test {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        //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();
        while(it.hasNext()){
            System.out.println(it.next() + " ");
        }
        System.out.println();
    }
}

【注意】

  1. ArrayList最长使用的遍历方法是:for遍历+小标以及foreach;
  2. 迭代器是一种设计模式的一种。

4.4ArrayList的扩容机制

下面的代码是否有缺陷?为什么?

//是否有缺陷
public class Test {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for(int i = 0; i < 100; i++) {
            list.add(i);
        }
    }
}

ArrayList是一个动态类型的顺序表,即:在插入元素的过程中,会自动的扩容。我们看看以下的源码。

 

 

 

 

 

 我们在创建ArrayList对象时,如果调用无参的构造方法,实际上并没有给它分配相应的空间,只有当add时,才会开始分配,所以创建对象时的大小为0;我们再调用add()方法,add()会先确定内部容量ensureCapacityInternal();再计算具体需要空间的数值calculateCapacity();在进行calculateCapacity()函数计算具体需要空间的数值时,我们判断这个数组是否为空,如果为空,返回默认值10或有效数据数+1中的较大值,我提的这种情况是返回10;然后进入ensureExplicitCapacity()确定数组的显式容量,需要的容量是10,但现在数组的容量是0,需要扩容,进入函数grow();这个函数grow()会扩大到原来数组的1.5倍,如果新的容量没有旧容量大,就扩大到传过来的参数(需要的空间大小),如果新的容量超过数组容量的上线,就直接扩大到上限,然后进行原数据的复制;最后新增了一个元素。

 5.模拟实现一个ArrayList

我们使用一个自定义的类来模拟实现一个ArrayList中所有常用的功能。

package demo2;

import java.util.Arrays;

/**
 * Describe:
 * User:lenovo
 * Date:2022-12-28
 * Time:18:50
 */
//ArrayList的模拟实现
//这个类中可能抛出IndexOutOfException,我们在使用的使用要进行异常捕捉
class MyArrayList{

    public int[] elem;
    public int usedSize;//用于记录储存了多少数据
    public static final int DEFAULT_SIZE = 5;

    //构造方法
    public MyArrayList() {
        this.elem = new int[DEFAULT_SIZE];
    }

    //为了方便测试,我们险些打印顺序表,注意:这不是顺序表中的方法。
    public void display() {
        for (int i = 0; i < usedSize; i++) {
            System.out.print(this.elem[i] + " ");
        }
        System.out.println();
    }

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

    //判断是否包含某种元素
    public boolean contains(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if(this.elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }

    //查找某个元素对应的位置
    public int indexOf(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if(this.elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }

    //新增元素,在数组的最后新增元素
    public void add(int data) {
        //判断空间是否存满
        if(this.isFull()) {
            resize();
        }
        this.elem[this.usedSize] = data;
        this.usedSize++;
    }
    /**
     * 判断数组是否存储满了
     * @return
     */
    private boolean isFull() {
        /*if(this.usedSize == this.elem.length) {
            return true;
        }
        return false;*/
        return this.usedSize == this.elem.length;
    }
    /**
     * 扩容
     * 用于为数组开辟新的空间
     */
    private void resize() {
        this.elem = Arrays.copyOf(this.elem, 2*this.elem.length);
    }

    //在pos位置新增新的元素
    public void add(int pos, int data) {
        checkIndex(pos);
        if(isFull()) {
            resize();
        }
        for(int i = usedSize - 1; i >= pos; i--) {
            elem[i+1] = elem[i];
        }
        elem[pos] = data;
        usedSize++;
    }
    /**
     * 用于检查传过来的下表是否合法
     * @param pos
     */
    private void checkIndex(int pos) {
        if(pos < 0 || pos > usedSize) {
            throw new IndexOutOfException("位置不合法,请检查位置的合法性!");
        }
    }

    //获取pos位置的元素
    public int get(int pos) {
        checkGetIdex(pos);
        return elem[pos];
    }
    /**
     * 检查要获取元素的下表是否合法
     */
    private void checkGetIdex(int pos) {
        if(pos < 0 || pos >= usedSize) {
            throw new IndexOutOfException("get获取元素时,位置不合法,请检查位置的合法性!");
        }
    }

    //给pos位置的元素设为value
    public void set(int pos, int value) {
        checkGetIdex(pos);
        this.elem[pos] = value;
    }

    //删除第一次出现的关键字key
    public boolean remove(int toRemove) {
        int index = indexOf(toRemove);
        if(index == -1) {
            System.out.println("没有这个数据!");
            return false;
        }
        for(int i = index; i < usedSize - 1; i++) {
            elem[i] = elem[i + 1];
        }
        usedSize--;
        elem[usedSize] = 0;
        return true;
    }

    //清空顺序表
    public void clear() {
        usedSize = 0;
    }
}
package demo2;

/**
 * Describe:
 * User:lenovo
 * Date:2022-12-28
 * Time:18:51
 */
public class IndexOutOfException extends RuntimeException{
    public IndexOutOfException() {
        super();
    }

    public IndexOutOfException(String message) {
        super(message);
    }
}

 

 

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

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

相关文章

[思考进阶]04 优秀的人,都在使用“微习惯”

除了要提升自己的技术能力&#xff0c;思维的学习和成长也非常非常重要&#xff0c;特推出此[思考进阶]系列&#xff0c;进行刻意练习&#xff0c;从而提升自己的认知。 我有个微信群&#xff0c;人很少&#xff0c;都是兄弟&#xff0c;每天打开电脑的时候&#xff0c;我都会有…

朴素贝叶斯分类的python的实现

文章目录介绍GaussianNB()参数介绍实例BernoulliNB()参数介绍实例MultinomialNB()参数介绍实例作者&#xff1a;王乐介绍 sklearn 是 scikit–learn 的简称,是一个基于 Python 的第三方模块。 sklearn 库集成了一些常用的机器学习方法,在进行机器学习任务时,并不需要实现算法,…

Java 并发编程解析 | 如何正确理解Java领域中的并发锁,我们应该具体掌握到什么程度?

写在开头 对于Java领域中的锁&#xff0c;其实从接触Java至今&#xff0c;我相信每一位Java Developer都会有这样的一个感觉&#xff1f;不论是Java对锁的实现还是应用&#xff0c;真的是一种“群英荟萃”&#xff0c;而且每一种锁都有点各有各的驴&#xff0c;各有各的本&…

#P13787. [NOIP2021] 报数

目录 一&#xff0c;题目 二&#xff0c;题意分析 三&#xff0c;做法 1.直接模拟题意 2&#xff0c;用筛法来解 3&#xff0c;正解(加上记忆化) 一&#xff0c;题目 二&#xff0c;题意分析 题目意思是说:每次输入一个数,然后先判断这个数是否为某一个十进制中包含7的数…

Redis 为什么这么快?

1.基于内存实现 Redis 是基于内存的数据库&#xff0c;跟磁盘数据库相比&#xff0c;完全吊打磁盘的速度。 2.高效的数据结构 Redis 一共有 5 种数据类型&#xff0c;String、List、Hash、Set、SortedSet。 不同的数据类型底层使用了一种或者多种数据结构来支撑&#xff0c;目的…

如何选择适合自己的进销存系统软件?

选择一款合适的进销存软件&#xff0c;可以有效解决企业生产经营中业务管理、分销管理、存货管理、营销计划的执行和监控、统计信息的收集等方面的业务问题。 进销存软件一直是一个热门话题&#xff0c;别急&#xff0c;我这就来给你介绍。 一、进销存管理软件 这里我要推荐…

计算机系统概述

计算机系统概述一、操作系统的概念1、定义2、功能和目标二 、操作系统特征1、并发性2、共享性3、虚拟性4、异步性三、操作系统的发展1、手工操作阶段2、批处理阶段——单道批处理系统2、批处理阶段——多道批处理系统3、实时操作系统四、运行机制和体系结构1、运行机制①指令②…

Gitea 的邮件通知

有这样的一个需求&#xff0c;当仓库中被推送或者更新代码的时候&#xff0c;希望在邮件中收到邮件通知。 Gitea 是可以实现这个功能的&#xff0c;但是在默认情况下这个功能是关闭的。 修改配置文件 根据 Gitea 的安装不同&#xff0c;我们的配置文件在&#xff1a;vi /etc…

【正点原子FPGA连载】第六章Petalinux设计流程实战摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第六章Petalinux…

【CS硕士三年级BetterBench】2022年终总结(脚踏实地,仰望星空)

2022年终总结 回忆录 2022年焦虑和快乐是这一年中最大的两种情绪了。焦虑主要是因为心里的三块石头&#xff0c;从年初就开始悬着。第一块石头&#xff0c;科研论文录用&#xff0c;第二个石头&#xff0c;拿到国奖&#xff0c;第三个石头是拿到满意的offer。目前只剩下最后一…

【Linux】多文件编译

目录 多文件编译 为什么要分两步编译&#xff1a; makefile文件 makefile里面安装 更改可调式版本 对比Windows中的VS 多文件编译 有以下文件 分两步&#xff1a; 第一步编译&#xff1a;.c->.o 第二步链接&#xff08;可以不用写头文件&#xff09;&#xff1a;.o-…

《图解TCP/IP》阅读笔记(第九章)—— 网络安全相关

第九章 网络安全 本章旨在介绍互联网中网络安全的重要性及其相关的实现技术。 本章的内容在我看来&#xff0c;并没有前几章那么重要&#xff0c;大概有所了解就好。 9.1 TCP/IP与网络安全 起初&#xff0c;TCP/IP只用于一个相对封闭的环境&#xff0c;后来才发展为并无太多…

Python编程 匿名函数,高阶函数

作者简介&#xff1a;一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.匿名函数 1.匿名函数介绍 匿名函数应用 匿名函数作返回值 匿名函数作…

【数据结构】超详细!从HashMap到ConcurrentMap,我是如何一步步实现线程安全的!

什么是HashMap&#xff1f; 在了解 HashMap 之前先了解一下什么是 Map&#xff1b; 什么是Map&#xff1f; 定义 Map 是一个用于存储 Key-Value 键值对的集合类&#xff0c;也就是一组键值对的映射&#xff0c;在 Java 中 Map 是一个接口&#xff0c;是和 Collection 接口同…

注解@Resource,注解@Qualifier

1.在进⾏类注⼊时&#xff0c;除了可以使⽤ Autowired 关键字之外&#xff0c;我们还可以使⽤ Resource 进⾏注⼊&#xff0c;如下代码所示&#xff1a; 运行结果&#xff1a; Autowired 和 Resource 的区别 出身不同&#xff1a;Autowired 来⾃于 Spring&#xff0c;⽽ Reso…

拾遗增补(二)——线程组

目录1.线程关联线程组&#xff1a;1级关联2.线程对象关联线程组&#xff1a;多级关联3.线程组自动归属特性4.获取根线程组5.线程组里加线程组6.组内的线程的批量停止7.递归与非递归取得组内对象可以把线程归属到某一个线程组中&#xff0c;线程组中可以有线程对象&#xff0c;也…

58.Python的递归函数

58.Python的递归函数 文章目录58.Python的递归函数1.递归的形象解释2.定义3.步骤4.终止条件5.优点6.缺点7.调用深度8.课堂实例9.计算n的阶乘9.1什么是阶乘9.2计算5&#xff01;1.递归的形象解释 我们首先看一段视频&#xff0c;来形象理解什么是递归。 视频作者&#xff1a;p…

完整的OpenDDS的发布订阅编写及源码(Windows)

一个完整的OpenDDS的发布订阅编写及源码,包括SimuMsg.idl、SimuMsg.mwc和SimuMsg.mpc,SimuMsgCommon_Export.h、publisher.cpp、subscriber.cpp、SimuMsgDataReaderListenerImpl.h和SimuMsgDataReaderListenerImpl.cpp、SimuMsgDataWriterListenerImpl.h和SimuMsgDataWriterL…

还有企业没有在用它嘛! 适配于多行业的管理系统,各企业之首选

在信息技术高速发展的现代社会&#xff0c;世界经济一体化和企业经营全球化已成为大势所趋。在此背景下&#xff0c;企业为增强自身的竞争力&#xff0c;就要强化管理&#xff0c;规范业务流程&#xff0c;提高透明度&#xff0c;加快商品资金周转&#xff0c;以及为流通领域信…

使用MariaDB线程池提高MySQL的扩展性

摘要&#xff1a;MySQL的线程池能够有效地解决大量短连接的性能问题&#xff0c;大幅提高MySQL数据库的扩展性。但官方MySQL的线程池在收费的企业版中才有&#xff0c;免费的社区版中没有这个功能&#xff0c;这里介绍MairaDB的线程池。 关于作者&#xff0c;姚远&#xff1a;…