ArrayList与顺序表

news2025/2/24 4:38:22

目录

​编辑

一、线性表

二、顺序表 

1、接口的实现

(1)打印顺序表

(2)新增元素

(3)判定是否包含某个元素

(4)查找某个元素对应的位置下标

(5)获取 pos 位置的元素

(6)获取顺序表长度

(7)给 pos 位置的元素设为 value【更新的意思 】

(8)在 pos 位置新增元素

(9)删除第一次出现的关键字key

(10)清空顺序表

三、ArrayList简介

 四、ArrayList使用

1、ArrayList的构造

2、ArrayList常见操作

3、ArrayList的遍历

4、ArrayList的扩容机制 

五、ArrayList的具体使用

六、ArrayList的问题及思考


一、线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

二、顺序表 

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

1、接口的实现

(1)打印顺序表

注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的

  public void display() {
        for (int i = 0; i < this.usedSize; i++) {
            System.out.print(this.elem[i] +" ");
        }
        System.out.println();
    }

(2)新增元素

默认在数据 最后新增

 public void add(int data) {
        //首先得判断满的情况
        if(isFull()) {
            resize();
        }
        this.elem[usedSize] = data;
        usedSize++;
    }
    public boolean isFull() {
        return usedSize == elem.length;
    }

(3)判定是否包含某个元素

  public boolean contains(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if(elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }

(4)查找某个元素对应的位置下标

  public int indexOf(int toFind) {
        for (int i = 0; i < this.usedSize; i++) {
            if(elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }

(5)获取 pos 位置的元素

  public int get(int pos) {
        if(!checkPos(pos)) {
            throw new PosOutBoundsException("get 获取数据时,位置不合法!");
        }
        return elem[pos];
    }

(6)获取顺序表长度

  public int size() {
        return this.usedSize;
    }

(7)给 pos 位置的元素设为 value【更新的意思 】

public void set(int pos, int value) {
        if(!checkPos(pos)) {
            throw new PosOutBoundsException("set 数据时,位置不合法!");
        }
        this.elem[pos] = value;
    }

    private boolean checkPos(int pos) {
        if(pos < 0 || pos >= usedSize) {
            return false;
        }
        return true;
    }

(8)在 pos 位置新增元素

 public void add(int pos, int data) {
        if(pos < 0 || pos > this.usedSize) {
            throw new PosOutBoundsException("add 元素的时候,pos位置不合法!");
        }
        if(isFull()) {
            resize();
        }
        //挪数据
        for (int i = this.usedSize-1; i >= pos ; i--) {
            this.elem[i+1] = this.elem[i];
        }
        //存数据
        this.elem[pos] = data;
        this.usedSize++;
    }

(9)删除第一次出现的关键字key

   public void remove(int toRemove) {
        if(isEmpty()) {
            return;
        }
        int index = indexOf(toRemove);
        if(index == -1) {
            return;//没有你要删除的数字
        }
        for (int i = index; i < usedSize-1; i++) {
            this.elem[i] = this.elem[i+1];
        }
        usedSize--;
        //elem[us] = null;
    }

(10)清空顺序表

 public void clear() {
        /*for (int i = 0; i < usedSize; i++) {
            this.elem[i] = null;
        }*/
        usedSize = 0;
    }

三、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 底层是一段连续的空间,并且可以动态扩容,是一个 动态 类型的顺序表

 四、ArrayList使用

1、ArrayList的构造

方法
解释
ArrayList ()
无参构造
ArrayList (Collection<? extends E> c)
利用其他 Collection 构建 ArrayList
ArrayList (int initialCapacity)
指定顺序表初始容量

现在,让我们来尝试创建一个顺序表:

public static void main(String[] args) {
// ArrayList创建,推荐写法
// 构造一个空的列表
        List<Integer> list1 = new ArrayList<>();
// 构造一个具有10个容量的列表
        List<Integer> list2 = new ArrayList<>(10);
        list2.add(1);
        list2.add(2);
        list2.add(3);
// list2.add("hello"); // 编译失败,List<Integer>已经限定了,list2中只能存储整形元素
// list3构造好之后,与list中的元素一致
        ArrayList<Integer> list3 = new ArrayList<>(list2);
// 避免省略类型,否则:任意类型的元素都可以存放,使用时将是一场灾难
        List list4 = new ArrayList();
        list4.add("111");
        list4.add(100);
        }

2、ArrayList常见操作

ArrayList 虽然提供的方法比较多,但是常用方法如下所示,需要用到其他方法时,可以自行查看 ArrayList 的帮助文档。

现在,我们来试着使用一下这些方法来完成一段代码的编写:

public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("JavaSE");
        list.add("JavaWeb");
        list.add("JavaEE");
        list.add("JVM");
        list.add("测试课程");
        System.out.println(list);
// 获取list中有效元素个数
        System.out.println(list.size());
// 获取和设置index位置上的元素,注意index必须介于[0, size)间
        System.out.println(list.get(1));
        list.set(1, "JavaWEB");
        System.out.println(list.get(1));
// 在list的index位置插入指定元素,index及后续的元素统一往后搬移一个位置
        list.add(1, "Java数据结构");
        System.out.println(list);
// 删除指定元素,找到了就删除,该元素之后的元素统一往前搬移一个位置
        list.remove("JVM");
        System.out.println(list);
// 删除list中index位置上的元素,注意index不要超过list中有效元素个数,否则会抛出下标越界异常
        list.remove(list.size()-1);
        System.out.println(list);
        // 检测list中是否包含指定元素,包含返回true,否则返回false
        if(list.contains("测试课程")){
        list.add("测试课程");
        }
// 查找指定元素第一次出现的位置:indexOf从前往后找,lastIndexOf从后往前找
        list.add("JavaSE");
        System.out.println(list.indexOf("JavaSE"));
        System.out.println(list.lastIndexOf("JavaSE"));
// 使用list中[0, 4)之间的元素构成一个新的SubList返回,但是和ArrayList共用一个elementData数组
        List<String> ret = list.subList(0, 4);
        System.out.println(ret);
        list.clear();
        System.out.println(list.size());
        }

3、ArrayList的遍历

ArrayList 可以使用三方方式遍历: for 循环 + 下标、 for each 、使用迭代器
使用for循环遍历:
for (int i = 0; i < list.size(); i++) {
        System.out.print(list.get(i) + " ");
        }
        System.out.println();

使用for each遍历:

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

使用迭代器遍历:

Iterator<Integer> it = list.listIterator();
        while(it.hasNext()){
        System.out.print(it.next() + " ");
        }
        System.out.println();
        }
注意:
1. ArrayList 最常使用的遍历方式是: for 循环 + 下标 以及 fo reach
2. 迭代器是设计模式的一种。

4、ArrayList的扩容机制 

ArrayList 是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容。以下是 ArrayList 源码中扩容方式:
Object[] elementData; // 存放元素的空间
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默认空间
private static final int DEFAULT_CAPACITY = 10; // 默认容量大小
public boolean add(E e) {
        ensureCapacityInternal(size + 1); // Increments modCount!!
        elementData[size++] = e;
        return true;
        }
private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
        }
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
        }
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
// overflow-conscious code
        if (minCapacity - elementData.length > 0)
        grow(minCapacity);
        }
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// 获取旧空间大小
        int oldCapacity = elementData.length;
// 预计按照1.5倍方式扩容
        int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果用户需要扩容大小 超过 原空间1.5倍,按照用户所需大小扩容
        if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
// 如果需要扩容大小超过MAX_ARRAY_SIZE,重新计算容量大小
        if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
// 调用copyOf扩容
        elementData = Arrays.copyOf(elementData, newCapacity);
        }
private static int hugeCapacity(int minCapacity) {
// 如果minCapacity小于0,抛出OutOfMemoryError异常
        if (minCapacity < 0)
        throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
        }

那么现在,我们对ArrayList源码中扩容的部分进行一个总结:

【总结】
1. 检测是否真正需要扩容,如果是调用 grow 准备扩容
2. 预估需要扩容的大小
        初步预估按照1.5 倍大小扩容
        如果用户所需大小超过预估1.5 倍大小,则按照用户所需大小扩容
        真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
3. 使用 copyOf 进行扩容

五、ArrayList的具体使用

在学习完ArrayList之后,我们可以使用ArrayList来完成对一些特定情况的使用,现在,我们来尝试使用ArrayList来编写一个简单的洗牌算法

大致思路如下:

我们可以先创建一个Card类,其中属性为牌的花色和牌面的数值,然后再将一整副牌都存进一个借用ArrayList创建的顺序表中,其次借用Random将扑克牌进行打乱处理,此时为了能够将牌顺利的发给三个人,我们可以在为每个人单独创建一个顺序表,并且再用一个顺序表来存储它们三个人分别的顺序表

代码的具体实现如下:

public class Card {
    public int rank; // 牌面值
    public String suit; // 花色
    @Override
    public String toString() {
        return String.format("[%s %d]", suit, rank);
    }
}
import java.util.List;
        import java.util.ArrayList;
        import java.util.Random;
public class CardDemo {
    public static final String[] SUITS = {"♠", "♥", "♣", "♦"};
    // 买一副牌
    private static List<Card> buyDeck() {
        List<Card> deck = new ArrayList<>(52);
        for (int i = 0; i < 4; i++) {
            for (int j = 1; j <= 13; j++) {
                String suit = SUITS[i];
                int rank = j;
                Card card = new Card();
                card.rank = rank;
                card.suit = suit;
                deck.add(card);
            }
        }
        return deck;
    }
    private static void swap(List<Card> deck, int i, int j) {
        Card t = deck.get(i);
        deck.set(i, deck.get(j));
        deck.set(j, t);
    }
    private static void shuffle(List<Card> deck) {
        Random random = new Random(20190905);
        for (int i = deck.size() - 1; i > 0; i--) {
            int r = random.nextInt(i);
            swap(deck, i, r);
        }
    }
    public static void main(String[] args) {
        List<Card> deck = buyDeck();
        System.out.println("刚买回来的牌:");
        System.out.println(deck);
        shuffle(deck);
        System.out.println("洗过的牌:");
        System.out.println(deck);
// 三个人,每个人轮流抓 5 张牌
        List<List<Card>> hands = new ArrayList<>();
        hands.add(new ArrayList<>());
        hands.add(new ArrayList<>());
        hands.add(new ArrayList<>());
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 3; j++) {
                hands.get(j).add(deck.remove(0));
            }
        }
        System.out.println("剩余的牌:");
        System.out.println(deck);
        System.out.println("A 手中的牌:");
        System.out.println(hands.get(0));
        System.out.println("B 手中的牌:");
        System.out.println(hands.get(1));
        System.out.println("C 手中的牌:");
        System.out.println(hands.get(2));
    }
}

六、ArrayList的问题及思考

1. ArrayList 底层使用连续的空间,任意位置插入或删除元素时,需要将该位置后序元素整体往前或者往后搬移,故时间复杂度为O(N)
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
3. 增容一般是呈 2 倍的增长,势必会有一定的空间浪费。例如当前容量为 100 ,满了以后增容到 200 ,我们再继续插入了5 个数据,后面没有数据插入了,那么就浪费了 95 个数据空间。
那么如何来解决这些问题呢?这就将与我们后面即将学到的链表有关了!
欢迎阅读下一期的链表博客

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

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

相关文章

基于QTableView中的MVD代理添加总结

目录 1、Qt中MVD说明 1.1 View 1.2 Delegate 1.3 Model/View的基本原理 2、代码是现实示例 2.1 设置样式文件 2.2 set base attribute 2.3 设置model 2.4 设置表头 2.5 设置数据 2.6 添加代理控件 2.6.1 添加 QSpinBox 代理 2.6.2 添加 QComboBox 代理 2.6.…

【JS】vis.js使用之vis-timeline使用攻略,vis-timeline在vue3中实现时间轴、甘特图

vis.js使用之vis-timeline使用攻略&#xff0c;vis-timeline实现时间轴、甘特图 1、vis-timeline简介2、安装插件及依赖3、简单示例4、疑难问题集合1. 中文zh-cn本地化2. 关于自定义class样式无法被渲染3. 关于双向数据绑定 vis.js是一个基于浏览器的可视化库&#xff0c;它提供…

深度探索vector

vector是什么 &#xff1f; vector就是一个可以自动扩充的array。 源码解析 vector主要是通过三个指针来维护的&#xff0c;分别是起点&#xff0c;当前终点&#xff0c;以及当前最大空间 sizeof(vector对象) 3 * 指针大小 vector每当遇到空间不同的情况&#xff0c;都会…

Windows逆向安全(一)之基础知识(十三)

Switch语句 先前讲了分支结构的if else形式&#xff0c;除此之外还有一种分支结构&#xff1a;switch 此次就来以反汇编的角度研究switch语句&#xff0c;并与if else进行比较 Switch语句的使用 有关Switch语句在vc6.0中生成的反汇编可分为4种情况&#xff0c;这4种情况的区…

不用科学上网,免费的GPT-4 IDE工具Cursor保姆级使用教程

1、Cursor 编辑器 可以直接官方网站下载&#xff1a;https://www.cursor.so/ &#xff08;这里以Mac为例&#xff09; 这是一款与OpenAI合作并且基于GPT4的新一代辅助编程神器&#xff0c;它支持多种文件类型&#xff0c;支持格式化文本、多种主题、多语言语法高亮、快捷键设…

react-7 组件库 Ant Design Mobile(移动端)

1.安装组件库 npm install --save antd-mobile 常用组件 tabbar 底部导航 Swiper 轮播图&#xff08;走马灯&#xff09; NavBar&#xff08;顶部返回累&#xff09; 配合 Dialog&#xff0c;Toast InfiniteScroll 无限滚动&#xff08;实现下拉刷新&#xff09; Skeleto…

ROS学习第九节——服务通信

1.基本介绍 服务通信较之于话题通信更简单些&#xff0c;理论模型如下图所示&#xff0c;该模型中涉及到三个角色: ROS master(管理者)Server(服务端)Client(客户端) ROS Master 负责保管 Server 和 Client 注册的信息&#xff0c;并匹配话题相同的 Server 与 Client &#…

远程控制电脑的软件哪个比较好用

有多种软件选项可用于远程控制计算机&#xff0c;最适合您的软件选项取决于您的具体需要和要求。 以下是一些最流行的远程控制软件选项及其功能和优势&#xff1a; TeamViewer TeamViewer 是使用最广泛的远程控制软件选项之一。 它具有用户友好的界面&#xff0c;并提供文件传…

Vue核心 Vue简介 初识

Vue核心 Vue简介 初识 1.1.Vue核心 Vue简介 初识 1.1.1.Vue核心 Vue简介 初识 英文官网 中文官网 1.1.2.介绍与描述 Vue 是一套用来动态构建用户界面的渐进式JavaScript框架 构建用户界面&#xff1a;把数据通过某种办法变成用户界面渐进式&#xff1a;Vue可以自底向上逐层…

YOLO V8实战入门篇 | Anaconda3 | ultralytics

目录 一、虚拟环境1.1 Anaconda3 安装1.2 创建适用YOLO V8的虚拟环境 二、YOLO v82.1 YOLO v8简介2.2 下载YOLO v8源码2.3 安装依赖 三、运行目标检测模型 一、虚拟环境 1.1 Anaconda3 安装 https://blog.csdn.net/weixin_42855758/article/details/122795125 参考这个链接&a…

NDK OpenCV 身份证信息离线识别

NDK系列之OpenCV 身份证信息离线识别技术实战&#xff0c;本节主要是通过OpenCV C库&#xff0c;实现身份证信息识别&#xff0c;如身份证号码识别&#xff0c;本节使用到的技术点同样适用于车牌号识别、银行卡号码识别等。 实现效果&#xff1a; 本节主要内容&#xff1a; 1…

数据库底层运行原理之——事务管理器

一般所有关系型数据库内部都有自己的事务机制&#xff0c;进程是如何保证每个查询在自己的事务内执行的&#xff0c;通过这篇文章来简单介绍一下。 我们可以理解为数据库是由多种相互交互的组件构成的&#xff0c;数据库一般可以用如下图形来理解&#xff1a; 事务管理器就是今…

两种方法,计算带地形起伏的地表面积

很多同学会经常计算占地面积, 就会用到投影面积计算和椭球体面积计算; 还有一些,需要去计算表面积, 也就是带地形起伏的地表面积, 这......咋办呢? 我们来介绍两种方法, 计算下面这个区域的地表面积—— 两种方法各有优势, 大家各取所需 方法一:表面体积工具 这…

【hello Linux】进程优先级

目录 1. 基本概念 2. 查看系统进程&#xff1a;&#xff08;包括优先级&#xff09; 2.1 使用命令查看系统进程 2.2 各字段分析 2.3 优先级的修正解释 2.4 使用 top 命令修改优先级 其他概念 Linux&#x1f337; 1. 基本概念 进程的优先权&#xff08; priority&#xff09;&…

Java版企业电子招投标系统源代码之电子招投标系统建设的重点和未来趋势

项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及…

网工神器:PNETLab模拟器踩坑过程(一)

0、前言 由于工作需要&#xff0c;想测试一下SD-WAN&#xff0c;手边既没有测试环境又没有测试设备。突然想到为什么不用模拟器测试。经过我一番操作好像发现了新大陆&#xff0c;没想到模拟器的世界发生了翻天覆地的变化。真是“一日学习一日功&#xff0c;一日不学十日空”。…

【IoT】以一款实际产品为例,来谈谈如何做商业计划分析

本篇内容以笔者早期刚转型做产品时,实际负责的一款产品为例,来谈谈如何做产品的商业计划分析。 首先简单介绍一下这款产品: 这是一款电子便签产品,目的是为了替换纸质便签,增加一些智能化的提醒控制。 该产品通过蓝牙与手机端连接,应用端配置好提醒信息后一键同步至产…

鼠标悬停发光按钮,流转边框

提示&#xff1a;css 动画实现&#xff0c;鼠标悬停发光按钮&#xff0c;流转边框。鼠标border可以旋转 前言 提示&#xff1a;以下是本篇文章的代码内容,供大家参考,相互学习 一、html代码 <!DOCTYPE html> <html><head><meta http-equiv"content…

企业信息化建设该怎么做?方向和手段都在这了

企业信息化建设该怎么做&#xff1f; 如果现在是十年前&#xff0c;我一定会说&#xff0c;做信息化需要寻找熟悉不同编程语言、有经验的程序员。 但是现在&#xff0c;如果不是特别复杂的信息化系统&#xff0c;其实公司完全可以使用零代码平台自主开发&#xff0c;不需要再…

[计算机图形学]光线追踪:加速结构(前瞻预习/复习回顾)

一、前言 上篇我们提到了&#xff0c;如果在光线追踪中&#xff0c;我们真的用每个像素发出的光线&#xff0c;以及在场景中弹射之后的光线与场景中的许多模型的上千万个三角形求交那将是一个非常慢的计算过程&#xff0c;所以&#xff0c;本篇我们将介绍一些加速结构来加速这个…