Java数据结构-----ArrayList与顺序表

news2024/12/19 19:53:36

目录

一、线性表

  二、顺序表

接口的实现

三、ArrayList简介        

四、 ArrayList使用       

1. ArrayList的构造

2.ArrayList常见操作

3. ArrayList的遍历

4.ArrayList的扩容机制

五、ArrayList的具体使用

简单的洗牌算法


一、线性表

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


  二、顺序表

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

接口的实现

public class SeqList {
private int[] array;
private int size;

SeqList(){ }// 默认构造方法

SeqList(int initcapacity){ }// 将顺序表的底层容量设置为initcapacity


public void add(int data) { }// 新增元素,默认在数组最后新增

public void add(int pos, int data) { }// 在 pos 位置新增元素

public boolean contains(int toFind) { return true; }// 判定是否包含某个元素

public int indexOf(int toFind) { return -1; }// 查找某个元素对应的位置

public int get(int pos) { return -1; }// 获取 pos 位置的元素

public void set(int pos, int value) { }// 给 pos 位置的元素设为 value

public void remove(int toRemove) { }//删除第一次出现的关键字key

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

public void clear() { }// 清空顺序表

public void display() { }// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
}


三、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的构造

eg.

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);
}bia

讲解第二个构造函数:ArrayList(Collection<? extends E> c)

表示的是这个构造函数接受一个Colletion类型的参数c,这个集合中的元素类型是E或者E的子类。

2.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循环+下标、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();
        while(it.hasNext()){
                System.out.print(it.next() + " ");
        }
        System.out.println();
}

注意:
1. ArrayList最常使用的遍历方式是:for循环+下标 以及 foreach。
2. 迭代器是设计模式的一种,后序容器接触多了再给大家铺垫。

4.ArrayList的扩容机制

下面代码有缺陷吗?为什么?

public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
                list.add(i);
        }
}

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;
}

【总结】
1. 检测是否真正需要扩容,如果是调用grow准备扩容。
2. 预估需要库容的大小。

  • 初步预估按照1.5倍大小扩容。
  • 如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容。
  • 真正扩容之前检测是否能扩容成功,防止太大导致扩容失败。

3. 使用copyOf进行扩容。

4.第一次add会分配大小为10的内存。


五、ArrayList的具体使用

简单的洗牌算法

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));
        }
}

运行结果:

刚买回来的牌:
[[♠ 1], [♠ 2], [♠ 3], [♠ 4], [♠ 5], [♠ 6], [♠ 7], [♠ 8], [♠ 9], [♠ 10], [♠ 11], [♠ 12], [♠ 13], [♥ 1], [♥ 2], [♥ 3], [♥ 4], [♥ 5], [♥ 6], [♥ 7],
[♥ 8], [♥ 9], [♥ 10], [♥ 11], [♥ 12], [♥ 13], [♣ 1], [♣ 2], [♣ 3], [♣ 4], [♣ 5], [♣ 6], [♣ 7], [♣ 8], [♣ 9], [♣ 10], [♣ 11], [♣ 12], [♣
13], [♦ 1], [♦ 2], [♦ 3], [♦ 4], [♦ 5], [♦ 6], [♦ 7], [♦ 8], [♦ 9], [♦ 10], [♦ 11], [♦ 12], [♦ 13]]
洗过的牌:
[[♥ 11], [♥ 6], [♣ 13], [♣ 10], [♥ 13], [♠ 2], [♦ 1], [♥ 9], [♥ 12], [♦ 5], [♥ 8], [♠ 6], [♠ 3], [♥ 5], [♥ 1], [♦ 6], [♦ 13], [♣ 12], [♦ 12],
[♣ 5], [♠ 4], [♣ 3], [♥ 7], [♦ 3], [♣ 2], [♠ 1], [♦ 2], [♥ 4], [♦ 8], [♠ 10], [♦ 11], [♥ 10], [♦ 7], [♣ 9], [♦ 4], [♣ 8], [♣ 7], [♠ 8], [♦ 9], [♠
12], [♠ 11], [♣ 11], [♦ 10], [♠ 5], [♠ 13], [♠ 9], [♠ 7], [♣ 6], [♣ 4], [♥ 2], [♣ 1], [♥ 3]]
剩余的牌:
[[♦ 6], [♦ 13], [♣ 12], [♦ 12], [♣ 5], [♠ 4], [♣ 3], [♥ 7], [♦ 3], [♣ 2], [♠ 1], [♦ 2], [♥ 4], [♦ 8], [♠ 10], [♦ 11], [♥ 10], [♦ 7], [♣ 9], [♦
4], [♣ 8], [♣ 7], [♠ 8], [♦ 9], [♠ 12], [♠ 11], [♣ 11], [♦ 10], [♠ 5], [♠ 13], [♠ 9], [♠ 7], [♣ 6], [♣ 4], [♥ 2], [♣ 1], [♥ 3]]
A 手中的牌:
[[♥ 11], [♣ 10], [♦ 1], [♦ 5], [♠ 3]]
B 手中的牌:
[[♥ 6], [♥ 13], [♥ 9], [♥ 8], [♥ 5]]
C 手中的牌:
[[♣ 13], [♠ 2], [♥ 12], [♠ 6], [♥ 1]]

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

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

相关文章

WordPress上传图片错误:不是合法的JSON响应

最近在进行WordPress迁移至新服务器的过程中&#xff0c;遭遇到一个棘手的问题&#xff0c;即在编辑文章并上传图片时&#xff0c;不断遭遇“此响应不是合法的JSON响应”的错误。经过多次验证和搜索&#xff0c;最终确定问题的根本原因并不在于禁用 Gutenberg 编辑器或安装经典…

ensp路由启动失败41错误及ensp安装【附安装包】(亲测!!!)

我用夸克网盘分享了 「eNSP安装教程&#xff08;非常详细&#xff09;从零基础入门到精通&#xff0c;看完这一篇就够了【附安装包】_ensp下载安装教程-CSDN博客.pdf」&#xff0c;点击链接即可保存。打开「夸克APP」在线查看&#xff0c;支持多种文档格式转换。 链接&#xf…

神经网络结构——CNN、RNN、LSTM、Transformer !!

文章目录 前言 一、什么是CNN 网络结构 解决问题 工作原理 实际应用 二、什么是RNN 网络结构 解决问题 工作原理 应用场景 三、什么是LSTM 网络结构 解决问题 工作原理 应用场景 四、什么是Transformer 网络结构 解决问题 工作原理 BERT GPT 前言 本文将从什么是CNN&#xff1…

现货黄金交易商运作模式大解密

也许现货黄金投资者都知道自己需要通过交易平台才能进入市场买卖&#xff0c;但很多人却并不知道交易平台如何处理自己的交易订单。其实交易商主要分为四种类型&#xff1a;交易员平台、无交易员平台、直接处理式平台以及电子通信网络平台&#xff0c;本文将为大家介绍一下它们…

WP外贸营销型网站模板

WordPress外贸独立站主题 简洁实用的WordPress外贸独立站主题&#xff0c;适合时尚服装行业搭建wordpress企业官网使用。 零件配件WordPress外贸建站模板 汽车行业零配件WordPress外贸建站模板&#xff0c;卖配件、零件的外贸公司可以使用的WordPress主题。 https://www.jia…

李沐动手学习深度学习——3.5练习

减少batch_size&#xff08;如减少到1&#xff09;是否会影响读取性能&#xff1f; 肯定会影响&#xff0c;计算机io性能而言&#xff0c;随着batch_size增大&#xff0c;读取越来越快&#xff0c;需要的时间越少。这里会涉及到计算机操作系统的知识点&#xff0c;内存与硬盘之…

获取 Windows 通知中心弹窗通知内容(含工具汉化)

目录 前言 技术原理概述 测试代码和程序下载连接 本文出处链接&#xff1a;https://blog.csdn.net/qq_59075481/article/details/136440280。 前言 从 Windows 8.1 开始&#xff0c;Windows 通知现在以 Toast 而非 Balloon 形式显示&#xff08; Bollon 通知其实现在是应用…

ARM总结and复习

安装交叉编译工具链 a. 为什么安装 因为arm公司的指令集在不断迭代升级&#xff0c;指令集日益增多,而架构是基于指令集研发的&#xff0c;所以架构不一样&#xff0c;指令集也不一样 eg:arm架构使用的是arm指令集 x86架构使用的是x86指令集 而我们日常开发环境中linux的架构…

QueryDet代码解析

配置文件 # 表示该配置文件是基于另一个配置文件BaseRetina.yaml进行扩展和覆盖的 _BASE_: "../BaseRetina.yaml" # 指定输出目录&#xff0c;训练过程中的日志、模型权重和评估结果将保存在该目录下。 OUTPUT_DIR: "work_dirs/visdrone_querydet" # 指定…

前端面试 跨域理解

2 实现 2-1 JSONP 实现 2-2 nginx 配置 2-2 vue 开发中 webpack自带跨域 2 -3 下载CORS 插件 或 chrome浏览器配置跨域 2-4 通过iframe 如&#xff1a;aaa.com 中读取bbb.com的localStorage 1)在aaa.com的页面中&#xff0c;在页面中嵌入一个src为bbb.com的iframe&#x…

Mybatis批量更新对象数据的两种方法

说明&#xff1a;遇到一次需要批量修改对象的场景。传递一个对象集合&#xff0c;需要根据对象ID批量修改数据库数据&#xff0c;使用的是MyBatis框架。查了一些资料&#xff0c;总结出两种实现方式。 创建Demo 首先&#xff0c;创建一个简单的Demo&#xff1b; &#xff08…

SOCKS55代理 VS Http代理,如何选择?

在使用IPFoxy全球代理时&#xff0c;选择 SOCKS55代理还是HTTP代理&#xff1f;IPFoxy代理可以SOCKS55、Http协议自主切换&#xff0c;但要怎么选择&#xff1f;为解决这个问题&#xff0c;得充分了解两种代理的工作原理和配置情况。 在这篇文章中&#xff0c;我们会简要介绍 …

java自动化之自动化框架项目(第五天-解析并执行初始化sql)

1.实现目标 先将常用变量占位符替换为实际值&#xff0c;然后解析并执行初始化sql&#xff0c;保证用例中的数据可用&#xff0c;这样不用每次执行测试前修改测试数据。 2.添加pom依赖 连接操作数据库&#xff08;pom.xml文件中添加&#xff09; <!-- https://mvnreposi…

深度学习PyTorch 之 RNN-中文多分类【代码解析】

上篇文章给出了RNN-中文多分类的代码实现&#xff0c;本次主要是对RNN的架构进行一个详细的解析 1、主代码 class RNN(nn.Module):def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim, n_layers, bidirectional, dropout):super().__init__()# 初始化函数…

白话transformer(一):注意力机制

前面我们分篇讲述了transformer的原理&#xff0c;但是对于很多刚接触transformer的人来说可能会有一点懵&#xff0c;所以我们接下来会分三篇文章用白话的形式在将transformer 讲一遍。 前文链接 Bert基础(一)–自注意力机制 Bert基础(二)–多头注意力 Bert基础(三)–位置编…

Linux安装JumpServer并结合内网穿透实现公网访问本地服务

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

全新攻击面管理平台

首页大屏 内测阶段&#xff0c;免费试用一个月 有兴趣体验的师傅&#xff0c;来长亭云图极速版群里找我 py

基于改进的YOLO算法在TT100K数据集上的交通标志目标检测

交通标志是道路交通管理中的重要元素&#xff0c;准确高效地检测交通标志对于智能交通系统具有重要意义。本文基于改进的YOLO算法&#xff0c;结合TT100K数据集&#xff0c;实现了交通标志的目标检测。通过优化网络结构和训练策略&#xff0c;提升了交通标志检测的准确性和效率…

vue 安装各种问题

新下载了个项目模板&#xff0c;安装包就遇到了各种各样问题 电脑&#xff1a;mac 使用npm i 等命令一直安装项目&#xff0c;然后一直报错 2534 info run canvas2.11.2 install node_modules/canvas node-pre-gyp install --fallback-to-build --update-binary 2535 info r…

rocky使用yum安装msyql8.0

先查看一下源是否有mysql和mysql的版本 yum list mysql* 直接yum install mysql-server 会安装相关7个包 安装完毕后systemctl start mysqld启动mysql 然后mysql_secure_installation配置权限 mysql8的配置稍微有点不一样&#xff0c;按照英文提示来就行&#xff0c;不会的…