当前位置: 首页 > news >正文

ArrayList与顺序表

1.线性表

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

2.顺序表

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

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

3.1 ArrayList的构造

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

 

 

 3.2ArrayList的遍历

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. 迭代器是设计模式的一种

3.3ArrayList的扩容机制 

每个ArrayList都有一个容量(capacity),如果容量不足,容器会自动增大底层数组的大小

        数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加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;
}

PS:Arrays.copyOf

// 扩容数组,将新长度设置为原长度的两倍 Integer[] expandedArray = Arrays.copyOf(originalArray, originalArray.length * 2);

缺点: 

        在ArrayList 任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后 搬移,时间复杂度为 O(n) ,效率比较低,因此 ArrayList 不适合做任意位置插入和删除比较多的场景

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基于Vue3和Node.js的完整增删改查项目实现教程:从后端封装到前端调用
  • 【Go - 每日一小问: 对未初始化的的 chan 进行读写,会怎么样?为什么?】
  • Android笔试面试题AI答之Kotlin常见考点总结
  • 【Android】Navigation动态设置Graph和Launch参数
  • Qt详解QPropertyAnimation创建属性动画
  • SQLserver中的日期时间
  • 牛津大学发布首篇《Transformer多模态学习》综述论文,23页pdf涵盖310篇文献全面阐述MMT的理论与应用
  • 智能废弃瓶子垃圾箱:城市环境的绿色守护者
  • javascript语句之switch
  • 鸿蒙(API 12 Beta3版)【使用ImagePacker完成图片编码】图片开发指导
  • Prompt + 工作流组件 = AI智能体:开启智能化新时代
  • SBB | 南京林业大学阮宏华团队揭示人工林发育过程中土壤有机碳积累的主要机制
  • 【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(十四)
  • 若依权限控制前端+后端实现思路梳理(PreAuthorize、hasPermi、v-hasPermi)
  • vivo手机短信删除了怎么恢复?恢复办法分享
  • 77. Combinations
  • CODING 缺陷管理功能正式开始公测
  • FastReport在线报表设计器工作原理
  • IP路由与转发
  • java中具有继承关系的类及其对象初始化顺序
  • LeetCode算法系列_0891_子序列宽度之和
  • Octave 入门
  • 搞机器学习要哪些技能
  • 基于webpack 的 vue 多页架构
  • 那些年我们用过的显示性能指标
  • 前嗅ForeSpider教程:创建模板
  • 算法-插入排序
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 一个JAVA程序员成长之路分享
  • 通过调用文摘列表API获取文摘
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • ​ArcGIS Pro 如何批量删除字段
  • #、%和$符号在OGNL表达式中经常出现
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (k8s)Kubernetes本地存储接入
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (八十八)VFL语言初步 - 实现布局
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (佳作)两轮平衡小车(原理图、PCB、程序源码、BOM等)
  • (五十)第 7 章 图(有向图的十字链表存储)
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • (自用)网络编程
  • .net 7 上传文件踩坑
  • .net core 控制台应用程序读取配置文件app.config
  • .NET gRPC 和RESTful简单对比
  • .NET 动态调用WebService + WSE + UsernameToken
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .NET成年了,然后呢?
  • .php文件都打不开,打不开php文件怎么办
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • [ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
  • [\u4e00-\u9fa5] //匹配中文字符