数据结构-ArrayList和顺序表

1.线性表

线性表是n个具有相同类型的数据元素所组成的有限序列,当n=0时,线性表为一个空表。

常见的线性表:顺序表,链表,栈和队列...

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

2.顺序表 

2.1 什么是顺序表 

顺序表是一段连续的存储单元来依次存储线性表中的数据元素。一般情况下采用数组存储。

2.2 顺序表的特点 

1.存储连续:顺序表的存储单元在内存中是连续的,这意味着每个元素的地址都是相邻连续的

2.随机访问:由于存储单元是连续的,可以通过元素的下标直接访问该位置的元素,时间复杂度为O(1)

3.存储密度高:顺序表的存储单元只存储数据元素本身,没有额外的存储开销

2.3 实现一个顺序表

public class MySequentialList{private int[] array;private int size;//默认构造方法MySequentialList(){}//将顺序表的容量设为initCapacityMySequentialList(int initCapacity){}//在数组末尾新增一个元素public void add(int data){}//在pos位置新增一个元素public void add(int pos,int data){}//判断是否包含某个元素public boolean contains(int toFind){}//查找某个元素对应的位置public int indexOf(int toFind){}//获取pos位置上的元素public int get(int pos){}//给pos位置上的元素设置为valuepublic void set(int pos,int value){}//删除第一次出现的关键字keypublic void remove(int toRemove){}//获取顺序表的长度public int size(){}//清空顺序表public void clear(){}
}

实现的思路:

1.MySequentialList(int initCapacity)

只需要将数组初始化大小为initCapacity即可

2.add(int data)

在数组最后的位置新增元素,要注意数组是否已满,如果已满,就要对数组进行扩容操作

3.add(int pos,int data)

首先要判断插入位置pos是否合法,如果pos小于0或pos大于数组的长度,则位置不合法要进行异常处理。如果位置合法,还要判断数组是否已满,进行插入操作时,要注意先将原pos以及pos后面的元素全都向后移动一位,再进行插入操作,如果直接插入,则只是单纯的元素覆盖。插入后,数组的长度加1

4.contains(int toFind)

判断是否包含某个元素,只需要遍历数组并进行比较,看数组中是否有存在要查找的元素,如果有,则返回true,没有则返回false

5.indexOf(int toFind)

遍历数组,看数组中是否存在要查找的元素,如果存在,则返回给元素位置的下标,如果不存在,则返回-1

6.get(int pos)

获取pos位置的元素,首先要判断pos位置是否合法,如果pos小于0或者pos大于数组的长度,则pos不合法,返回-1。如果合法,直接返回下标为pos的元素

7.set(int pos,int value)

给pos位置的元素设置为value,单纯的进行对应下标元素覆盖即可

8.remove(int toRemove)

删除第一次出现关键字key,遍历数组,看key是否存在。如果不存在,则返回-1。如果存在,只需要将该位置后面的所有元素先前移动一位即可

9.size()

直接返回数组的有效长度,有效长度指的是数组中有效元素的个数,不是单纯的数组长度

10.clear()

清空顺序表,重新初始化数组,并将数组的长度置为0

我们后续以ArrayList的实现为例。

3.ArrayList

3.1 什么是ArrayList

在集合框架中,ArrayList是 Java 标准库中的一个非常常用的类,它实现了 List接口,提供了动态数组的功能。 ArrayList内部使用数组来存储元素,因此它具备顺序表的所有特点,是顺序表的一种实现。

 

说明:

1.ArrayList 是以泛型的方式实现的,使用时必须要先实例化

2.ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问

3.ArrayList实现了Cloneable接口,表明ArrayList是可以clone的

4.ArrayList实现了Serializable接口,表面ArrayList是支持序列化的

5.ArrayList是线程不安全的,在单线程下可以使用

6.ArrayList是通过动态的数组实现的,是一段连续的空间,并且可以进行扩容

3.2 ArrayList的构造方法

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

 代码演示:

public class Test {public static void main(String[] args) {//无参构造List<Integer> list1=new ArrayList<>();//利用其他Collection构建ArrayListArrayList<Integer> arrayList=new ArrayList<>();List<Integer> list2=new ArrayList<>(arrayList);//指定顺序表容量List<Integer> list3=new ArrayList<>(10);}
}

3.3 ArrayList的常见操作

ArrayList常见的方法

方法解释
boolean add(E,e)在尾部插入元素e
void add(int index,E e)将元素e插入到下标为index的位置
boolean addAll(Collection<? extends E> c)在尾部插入c中的所有元素
E remove(int index)删除index位置的元素
boolean remove(Object o)删除遇到第一个为o的元素
E get(int index)获取下表为index的元素
E set(int index,E e)将下表为index位置的元素设置为e
void clear()清空所有元素
boolean contains(Object o)判断o是否在线性表中
int indexOf(Object o)返回第一个o所在的下标
int lastIndexOf(Object o)返回最后一个o所在的下标
List<E> subList(int fromIndex,int toIndex)截取部分list

代码演示:

import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) {List<Integer> list=new ArrayList<>();System.out.println(list);//在尾部插入元素list.add(1);list.add(5);list.add(3);list.add(5);list.add(10);System.out.println(list);//在下标为2的位置增加元素list.add(2,4);System.out.println(list);//删除下标为2的元素list.remove(2);System.out.println(list);//删除遇到的第一个5元素Integer a=5;list.remove(a);System.out.println(list);//获取下标为1的元素int e=list.get(1);System.out.println(e);//将下标为1的元素设置为99list.set(1,99);System.out.println(list);//判断5是否在线性表中System.out.println(list.contains(5));//返回第一个5所在的下标e=list.indexOf(5);System.out.println(e);//返回最后一个5所在的下标e= list.lastIndexOf(5);System.out.println(e);//截取部分list,左闭右开List<Integer> newList=new ArrayList<>();newList=list.subList(1,3);System.out.println(newList);//将newList中的元素全部添加入list中list.addAll(newList);System.out.println(list);//清空listlist.clear();System.out.println(list);}
}

3.4 ArrayList的遍历 

ArrayList的遍历方式主要分为3种:

1.for循环搭配下标

2.foreach

3.使用迭代器

public class Test {public static void main(String[] args) {List<String> list=new ArrayList<>();list.add("hajimi");list.add("is");list.add("a");list.add("cat");//使用for循环搭配下标for(int i=0;i<list.size();i++){System.out.print(list.get(i)+" ");}System.out.println();//使用foreach遍历for(String s:list){System.out.print(s+" ");}System.out.println();//使用迭代器遍历Iterator<String> it=list.listIterator();while(it.hasNext()){System.out.print(it.next()+" ");}}
}

4.深度理解ArrayList 的扩容机制

观察原码:

int DEFAULT_CAPACITY表示默认的容量大小

Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA表示默认的空间

Object[] elementData表示存放元素的空间

 ArrayList的无参构造函数,将elementData初始化为DEFAULTCAPACITY_EMPTY_ELEMENTDATA,这是一个空数组,用于创建一个具有默认容量为 10的空ArrayList

ArrayList的add方法首先调用ensureCapacityInternal(size+1),size表示当前顺序表的有效长度,size+1表示添加元素后应有的长度 

 size+1的值传递给ensureCapacityInternal的形参minCapacity,ensureCapacityInternal先调用calculateCapacity(Object[] element,int minCapacity)传入存放元素的空间elementData和minCapacity

calculateCapacity(Object[] elementData,int minCapacity)用来计算ArrayList需要增长到的最小容量。判断elementData是否等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA,如果相等则意味着ArrayList当前没有分配任何容量,是空的。在这种情况下,方法返回DEFAULT_CAPACITY(10)和minCapacity中的较大值。如果element不是空数组,则意味着ArrayList已经有了一些容量,这种情况下,直接返回minCapacity,可以保证它至少增长到minCapacity即可

 calculateCapacity的返回值传递给ensureExplicitCapacity的形参minCapacity,判断当前是否需要扩容,如果minCapacity大于数组的长度,则表示需要进行扩充

 ArrayList的扩容函数grow(int minCapacity)用于增加ArrayList的内部数组elementData的容量,使其至少容纳minCapacity个元素。

int newCapacity=oldCapacity+(oldCapacity >> 1)计算新的容量,通常是当前容量的1.5倍

if(newCapacity - minCapacity < 0)判断新容量是否满足最小的需求,如果计算出的容量仍然小于最小的容量,则将newCapacity设置为minCapacity

if(newCapacity-MAX_ARRAY_SIZE > 0)检查新容量是否超出最大数组的大小,如果超过了调用hugeCapacity处理这种情况(将新容量设为Integer.MAX_VALUES)

elementData = Arrays.copyOf(elementData,newCapacity)使用copyOf创建一个新的数组,并将就数组中的元素复制到新数组中。

总结:

1.首先判断是否需要进行扩容,如果需要进行扩容,调用grow方法

2.计算扩容所需的最小的容量

初步预估按照1.5倍大小进行扩容

如果用户所需大小大于预估的1.5倍,则按照用户所需大小进行扩容

扩容前检查是否可以扩容成功,防止太大导致扩容失败

3.使用Arrays.copyOf进行扩容

5.实现一个ArrayList

package datastructure;import java.util.Arrays;public class MyArrayList {public int[] elem;public int usedSize;//0//默认容量private static final int DEFAULT_SIZE = 2;public MyArrayList() {this.elem = new int[DEFAULT_SIZE];}/*** 打印顺序表:*   根据usedSize判断即可*/public void display() {for(int i=0;i<this.usedSize;i++){System.out.print(elem[i]+" ");}System.out.println();}// 新增元素,默认在数组最后新增public void add(int data) {if(isFull()){//扩容this.elem=Arrays.copyOf(this.elem,2*this.elem.length);}this.elem[this.usedSize]=data;this.usedSize++;}/*** 判断当前的顺序表是不是满的!* true:满   false代表空*/public boolean isFull() {if(this.usedSize==this.elem.length){return true;}return false;}private boolean checkPosInAdd(int pos) {if(pos<0||pos>usedSize){System.out.println("位置不合法");return false;}return true;//合法}// 在 pos 位置新增元素//移动数据,从后向前防止数值被覆盖public void add(int pos, int data) {if(pos<0||pos>this.usedSize){System.out.println("位置不合法");return;}if(isFull()){//扩容this.elem=Arrays.copyOf(this.elem,2*this.elem.length);}for(int i=this.usedSize-1;i>=pos;i--){this.elem[i+1]=this.elem[i];}this.elem[pos]=data;usedSize++;}// 判定是否包含某个元素public boolean contains(int toFind) {for(int i=0;i<this.usedSize;i++){if(elem[i]==toFind){return true;}}return false;}// 查找某个元素对应的位置public int indexOf(int toFind) {if(isEmpty()){System.out.println("表中没有元素");return -1;}for(int i=0;i<usedSize;i++){if(elem[i]==toFind){return i;}}System.out.println("没找到");return -1;}// 获取 pos 位置的元素public int get(int pos) {if(pos<0&&pos>=usedSize){System.out.println("输入不合法!");return -1;}if(!isEmpty()){return elem[pos];}return -1;}private boolean isEmpty() {if(usedSize==0){return true;}return false;}// 给 pos 位置的元素设为【更新为】 valuepublic void set(int pos, int value) {if(pos<0||pos>=usedSize)return;elem[pos]=value;}/*** 删除第一次出现的关键字key* @param key*/public void remove(int key) {int index=indexOf(key);if(index==-1){return;}for(int i=index;i<usedSize-1;i++){this.elem[i]=this.elem[i+1];}this.usedSize--;}// 获取顺序表长度public int size() {return this.usedSize;}// 清空顺序表public void clear() {this.usedSize=0;}
}

6.ArrayList的特点

1.基于数组实现:

ArrayList使用一个动态数组来存储元素

2.动态数组容量

ArrayList可以根据添加元素的情况进行自动扩容,默认情况下是按照当前容量的1.5倍进行扩容

3.随机访问效率高,时间复杂度为O(1)

ArrayList基于数组实现,支持随机访问,时间复杂度为O(1)

4.插入和删除操作时间复杂度为O(n)

在ArrayList的中间位置插入或删除元素效率不高,这些操作会移动插入点之后的所有元素,时间复杂度为O(n),但是在末尾插入或删除元素的时间复杂度为O(1)

5.允许有重复的元素

6.允许存储null元素

7.ArrayList是线程不安全的

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

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

相关文章

红外热成像之无人机载荷

电力巡检 相较于传统的人工电力巡线方式&#xff0c;无人机巡检能够在高空对人工难以达到或无法检测的设备进行检测&#xff0c;实现了电子化、信息化、智能化巡检&#xff0c;可以提高巡检的工作效率和应急抢险水平。 森林防火 无人机搭载红外光电系统能在森林高空进行全天候监…

Typescript新特性关键字readyonly详细解读

readonly修饰符&#xff1a;首先是一个关键字&#xff0c;对类中的属性成员进行修饰&#xff0c;修饰后&#xff0c;该属性成员&#xff0c;就不能在外部被随意的修改了 一 构造函数中&#xff0c;可以对只读的属性成员的数据进行修改 (()>{//定义一个类型class Person {/…

linux tty 终端

linux tty 终端 一、终端二、终端的类型1、虚拟终端2、伪终端 pty3、串口终端4、控制终端 三、内核中的终端1、open2、write3、read1. 读取数据2. 数据返回3. 常见的 termios 四、编程实验 作者: baron 个人博客: baron-z.cn 基于网站原因csdn上面的图片有压缩, 如果不是很清楚…

在 vscode + cmake + GNU 工具链的基础上配置 JLINK

安装 JLINK JLINK 官网链接 下载安装后找到安装路径下的可执行文件 将此路径添加到环境变量的 Path 中。 创建 JFlash 项目 打开 JFlash&#xff0c;选择新建项目 选择单片机型号 在弹出的窗口中搜索单片机 其他参数根据实际情况填写 新建完成&#xff1a; 接下来设置…

智能建筑时代的核心选择——基于SAIL-RK3576核心板的AI边缘计算网关方案

随着智能建筑技术的不断发展&#xff0c;建筑设备正日益向“智慧化”迈进。传统的建筑管理系统往往依赖中央服务器和云端平台进行数据处理和控制&#xff0c;但在实时监控、安防及能耗管理等关键环节&#xff0c;延迟和数据安全问题依然存在。此外&#xff0c;物联网设备数量激…

python列表如何不重复

python列表不重复的方法&#xff1a; python内置的set&#xff08;&#xff09;方法可以去掉列表里面重复的元素&#xff0c;调用该方法就可以让python列表不重复了 a [23, 15, 15, 56, 89, 89, 56] a set(a) print(a) 运行结果如下&#xff1a;

【Redis】事务的概念及用法

事务的概念及用法 什么是事务事务的操作开启事务&#xff08;MULTI&#xff09;执行事务&#xff08;EXEC&#xff09;中止事务&#xff08;DISCARD&#xff09;为事务提供检查&#xff08;WATCH&#xff09;取消对key的监控&#xff08;UNWATCH&#xff09; 为什么Redis不支持…

为AI聊天工具添加一个知识系统 之54 为事务处理 设计 基于DDD的一个 AI操作系统 来处理维度

本文要点 要点 Architecture程序 它被设计为一个双面神结构的控制器&#xff0c;它的两侧一侧编译执行另一侧 解释执行&#xff0c;自已则是一个 翻译器--通过提供两个不同取向之间 的 结构映射的显示器&#xff08;带 图形用户接口GUI和命令行接口CLI 两种 接口&#xff09…

两份PDF文档,如何比对差异,快速定位不同之处?

PDF文档比对是通过专门的工具或软件&#xff0c;自动检测两个PDF文件之间的差异&#xff0c;并以可视化的方式展示出来。这些差异可能包括文本内容的修改、图像的变化、表格数据的调整、格式的改变等。比对工具通常会标记出新增、删除或修改的部分&#xff0c;帮助用户快速定位…

Flutter:搜索页,搜索bar封装

view 使用内置的Chip简化布局 import package:chenyanzhenxuan/common/index.dart; import package:ducafe_ui_core/ducafe_ui_core.dart; import package:flutter/material.dart; import package:get/get.dart; import package:tdesign_flutter/tdesign_flutter.dart;import i…

深度学习基础知识

深度学习是人工智能&#xff08;AI&#xff09;和机器学习&#xff08;ML&#xff09;领域的一个重要分支&#xff0c;以下是对深度学习基础知识的归纳&#xff1a; 一、定义与原理 定义&#xff1a;深度学习是一种使计算机能够从经验中学习并以概念层次结构的方式理解世界的机…

【Elasticsearch】腾讯云安装Elasticsearch

Elasticsearch 认识Elasticsearch安装Elasticsearch安装Kibana安装IK分词器分词器的作用是什么&#xff1f;IK分词器有几种模式&#xff1f;IK分词器如何拓展词条&#xff1f;如何停用词条&#xff1f; 认识Elasticsearch Elasticsearch的官方网站如下 Elasticsearch官网 Ela…

Ubuntu 24.04 LTS 通过 docker 安装 nextcloud 搭建个人网盘

准备 Ubuntu 24.04 LTSUbuntu 空闲硬盘挂载Ubuntu 安装 Docker DesktopUbuntu 24.04 LTS 安装 tailscale [我的Ubuntu服务器折腾集](https://blog.csdn.net/jh1513/article/details/145222679。 安装 nextcloud 参考 Ubuntu24.04系统Docker安装NextcloudOnlyoffice _。 更…

ThinkPHP 8的多对多关联

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用VS Code开发ThinkPHP项目-CSDN博客 编程与应用开…

Spring Boot 整合 Knife4j:打造更优雅的 API 文档

在现代 Web 应用开发中&#xff0c;API 文档的重要性不言而喻。清晰、准确、易用的 API 文档不仅可以方便开发者理解和使用 API&#xff0c;还能提高团队协作效率。Knife4j 是一个基于 Swagger 的增强型 API 文档工具&#xff0c;它可以为 Spring Boot 项目生成美观、易于交互的…

计算机网络 (53)互联网使用的安全协议

一、SSL/TLS协议 概述&#xff1a; SSL&#xff08;Secure Sockets Layer&#xff09;安全套接层和TLS&#xff08;Transport Layer Security&#xff09;传输层安全协议是工作在OSI模型应用层的安全协议。SSL由Netscape于1994年开发&#xff0c;广泛应用于基于万维网的各种网络…

如何利用边缘节点服务打造极致用户体验?

随着互联网和数字化技术的飞速发展&#xff0c;用户对网络访问速度和服务体验的要求也在不断提高。在一个信息快速传播的时代&#xff0c;延迟过高或访问卡顿的问题会直接影响用户体验&#xff0c;甚至导致用户流失。因此&#xff0c;企业如何优化网络性能、提升用户访问速度&a…

React的应用级框架推荐——Next、Modern、Blitz等,快速搭建React项目

在 React 企业级应用开发中&#xff0c;Next.js、Modern.js 和 Blitz 是三个常见的框架&#xff0c;它们提供了不同的特性和功能&#xff0c;旨在简化开发流程并提高应用的性能和扩展性。以下是它们的详解与比较&#xff1a; Next、Modern、Blitz 1. Next.js Next.js 是由 Ve…

如何在龙蜥 OS(AliOS)上安装极狐GitLab?

本文分享如何在龙蜥操作系统&#xff08;AliOS&#xff09;&#xff08;包括 RHCK 和 ANCK 两种&#xff0c;两种方式的安装流程一样&#xff09;上安装极狐GitLab&#xff1f; 前提条件 一个安装了龙蜥操作系统的云服务器 可以查看 /etc/os-release中的信息&#xff0c;确认…

if_yellow_only_restart_upgrading_nodes_with_unassigned_replicas

目录标题 遇事不决&#xff0c;上githubif_yellow_only_restart_upgrading_nodes_with_unassigned_replicas问题分析如何解决并使集群恢复到正常状态1. **检查和分配未分配的副本分片**2. **查看节点日志**3. **检查资源配置**4. **手动升级节点**5. **修改 if_yellow_only_res…