java数据结构集合复习之ArrayList与顺序表

前言: 这是我最一年学习java的一部分的回顾总结

1.List

1.1什么是List?

在框架集合中,List是一个接口,继承自Collection。
在这里插入图片描述

Collection也是一个接口,该接口中规范了后序容器中常用的一些方法,具体如下所示
在这里插入图片描述
在这里插入图片描述

--------
boolean add(E e)尾插 e
void add(int index, E element)将 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 element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List subList(int fromIndex, int toIndex)截取部分 list

站在数据结构的角度来看,List就是一个线性表,即n个具有相同类型元素的有限序列,在该序列上可以执行增删改查以及变量等操作。

1.2 List的使用

List是个接口,并不能直接用来实例化
如果要使用,必须去实例化List的实现类

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;public class ListExample {public static void main(String[] args) {// 使用 ArrayList 实现类List<String> arrayList = new ArrayList<>();arrayList.add("Apple");arrayList.add("Banana");arrayList.add("Orange");System.out.println("ArrayList: " + arrayList);// 使用 LinkedList 实现类List<String> linkedList = new LinkedList<>();linkedList.add("Mango");linkedList.add("Kiwi");linkedList.add("Grape");System.out.println("LinkedList: " + linkedList);}
}

List 不能直接实例化是因为接口本身只是一种规范或契约,它定义了一组方法的签名,但并没有提供这些方法的具体实现。
接口的主要目的是为了实现多态性和代码的解耦。通过定义接口,不同的类可以实现相同的接口,从而以统一的方式进行处理。 打个比方,想象 List
接口是一个菜谱,它只规定了要有哪些菜(方法),但没有告诉你具体怎么做这些菜(方法的实现)。只有具体的厨师(实现类),比如 ArrayList
或者 LinkedList ,才能按照这个菜谱做出实际的菜肴(实现方法)。

ArrayList与顺序表

2.1 线性表

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

在这里插入图片描述

2.2 顺序表

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

下面是手动实现一个顺序表的实现

package com;import java.util.Arrays;public class SeqList {private int[] array;//记录当前顺序表当中 有多少个有效的数据private int size;private static final int INIT_CAPACITY = 5;// 默认构造方法 将顺序表的底层容量设置为INIT_CAPACITYpublic SeqList(){this.array = new int[INIT_CAPACITY];}//判断当前顺序表是否满了 注意在进行新增操作是都要考虑数组是否需要判断满表public boolean isFull(){//返回当前表中的元素个数与当前表的长度作比较若相等是ture,反之falsereturn size == array.length;}//给数组扩容 注意在进行新增操作是都要考虑数组是否需要扩容private void resize(){array = Arrays.copyOf(array,2*array.length);}// 新增元素,默认在数组最后新增public void add(int data){if (isFull()){resize();}this.array[size] = data;//将当前指针位置+1,每次新增操作都需要size++;}// 在 pos 位置新增元素public void add(int pos,int data){//判断pos位置合不合法if (pos<0 || pos>this.size){throw new PosOutBoundsException("add 元素的时候,pos位置不合法!");}if(isFull()){resize();}for (int i = size-1; i >= pos; i--) {array[i+1] = array[i];}array[pos] = data;size++;}// 判定是否包含某个元素public boolean contains(int toFind) {for (int i = 0; i <this.size; i++) {if(array[i] == toFind){return true;}}return false;}// 查找某个元素对应的位置public int indexOf(int toFind) {for (int i = 0; i < this.size; i++) {if (array[i] == toFind){return i;}}return -1;}// 获取 pos 位置的元素public int get(int pos) {if (pos<0 || pos>this.size){throw new PosOutBoundsException("pos位置不合法!");}return array[pos];}// 给 pos 位置的元素设为 valuepublic void set(int pos, int value) {if (pos<0 || pos>this.size){throw new PosOutBoundsException("pos位置不合法!");}this.array[pos] = value;}//删除第一次出现的关键字keypublic void remove(int toRemove) {if (isEmpty()){return;}int index = indexOf(toRemove);if (index == -1){System.out.println("没有你要删除的数据");}for (int i = index; i < this.size-1; i++) {this.array[i] = this.array[i+1];}size--;}// 获取顺序表长度public int size() {return size;}// 清空顺序表public void clear() {size=0;}// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的public void display() {for (int i = 0; i < this.size; i++) {System.out.println(this.array[i]+ " ");}}public boolean isEmpty(){return this.size == 0;}public static void main(String[] args) {SeqList seqList = new SeqList();seqList.add(1);seqList.add(2);seqList.add(3);seqList.add(4);seqList.add(1,10000);seqList.display();}
}

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

2.4ArrayList的扩容机制

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

private static final int DEFAULT_CAPACITY = 10;// 默认容量大小
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};// 默认空间
transient Object[] elementData; 存放元素的空间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进行扩容

2.5 ArrayList的小练习

给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。
杨辉三角
解法:

 public List<List<Integer>> generate(int numRows) {List<List<Integer>> allList = new ArrayList<>();for (int i = 0; i < numRows; i++) {List<Integer> list = new ArrayList<>();list.add(1);for (int j = 1; j < i; j++) {list.add(allList.get(i-1).get(j-1)+allList.get(i-1).get(j));}if(i != 0){list.add(1);}allList.add(list);}return allList;}

2.6ArrayList的问题及思考

问题:

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

思考:
如何解决以上问题呢?

  1. 对于频繁的插入或删除元素 我们可以适合的数据结构,例如LinkedList。LinkedList底层使用链表实现,在链表中间进行插入和删除操作的时间复杂度为 O(1),但它在随机访问元素时的性能相对较差。

  2. 针对增容带来消耗的问题:
    如能预先估计集合可能需要存储的元素数量,在创建ArrayList时指定合适的初始容量,可以减少扩容的次数。或者采用内存池技术:创建一个内存池来管理内存分配和释放。当需要扩容时,从内存池中获取预先分配好的合适大小的内存块,而不是每次都进行新的内存申请和释放操作。

  3. 关于增容导致的空间浪费问题:
    一种解决思路是使用自定义的动态数组实现,根据实际元素数量更精确地控制扩容策略,而非简单地按照固定倍数扩容。例如,可以根据当前元素数量和一个预设的负载因子来决定是否扩容以及扩容的幅度。但这种方式需要自己实现动态数组的相关逻辑,增加了编程的复杂性

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

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

相关文章

[pwn]静态编译

静态编译 1. 栈足够大的情况下 程序在ida打开后&#xff0c;左侧的函数栏目没有红色&#xff08;系统调用的函数&#xff09;&#xff0c;而只有一些静态函数&#xff0c;通常这类文件的大小会必普通的pwn题程序要大得多。 这种静态编译的题没有调用库函数&#xff0c;也就没…

百度云智能媒体内容分析一体机(MCA)建设

导读 &#xff1a;本文主要介绍了百度智能云MCA产品的概念和应用。 媒体信息海量且复杂&#xff0c;采用人工的方式对视频进行分析处理&#xff0c;面临着效率低、成本高的困难。于是&#xff0c;MCA应运而生。它基于百度自研的视觉AI、ASR、NLP技术&#xff0c;为用户提供音视…

Vue 性能革命:揭秘前端优化的终极技巧;Vue优化技巧,解决Vue项目卡顿问题

目录 Vue优化路径 一、使用key 二、使用冻结对象 三、使用函数式组件 四、使用计算属性 五、使用非实时绑定的表单项 六、保持对象引用稳定 6.1、保持对象引用稳定定义 6.2、保持对象引用稳定与不稳定的例子 6.3、vue2判断数据是否变化是通过hasChanged函数实现的 ①…

2024年【四川省安全员B证】考试及四川省安全员B证考试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【四川省安全员B证】考试及四川省安全员B证考试题&#xff0c;包含四川省安全员B证考试答案和解析及四川省安全员B证考试题练习。安全生产模拟考试一点通结合国家四川省安全员B证考试最新大纲及四川省安全员B证…

C语言 -- 操作符详解​

C语言 -- 操作符详解​ 1. 操作符的分类2. 二进制和进制转换​2.1 2进制转10进制​2.1.1 10进制转2进制数字​ 2.2 2进制转8进制和16进制​2.2.1 2进制转8进制​2.2.2 2进制转16进制​ 3. 原码、反码、补码​4. 移位操作符​4.1 左移操作符​ 4.2 右移操作符​5. 位操作符&…

Linux_共享内存通信

目录 1、共享内存原理 2、申请共享内存 2.1 ftok 2.2 测试shmget、ftok 2.3 查看系统下的共享内存 3、关联共享内存 3.1 测试shmat 4、释放共享内存 4.1 测试shmctl 5、实现共享内存通信 6、共享内存的特性 结语 前言&#xff1a; 在Linux下&#xff0c;有一…

爆!Java高级特性之Stream API详解

爆&#xff01;Java高级特性之Stream API详解 Java 8引入的Stream API可以说是一个革命性的特性,让我们告别了又臭又长的for循环,迎来了函数式编程的春天。今天就让我们来一起深入了解这个让人又爱又恨的Stream API吧! 什么是Stream? Stream就像一个高级的迭代器,允许我们以…

分支与循环

目录 1. if语句 1&#xff09;if 2) else 3&#xff09;分支中包含多条语句 4&#xff09;if嵌套 2.关系操作符 3.条件操作符 4.逻辑操作符&#xff1a;&& || ! 1) 逻辑取反运算符 !​编辑 2 与运算符​编辑 3) 或运算符​编辑 4) 闰年的判断 5) 短路 …

若依 Vue 前端分离 3.8.8 版中生成的前端代码中关于下拉框只有下拉箭头的问题

生成代码修改前 <el-form-item label"课程学科" prop"subject"><el-select v-model"queryParams.subject" placeholder"请选择课程学科" clearable><el-optionv-for"dict in course_subject":key"dict…

【博士每天一篇文献-算法】Adult neurogenesis acts as a neural regularizer

阅读时间&#xff1a;2023-12-20 1 介绍 年份&#xff1a;2022 作者&#xff1a;Lina M. Tran&#xff0c;Adam Santoro&#xff0c;谷歌DeepMind 期刊&#xff1a; Proceedings of the National Academy of Sciences 引用量&#xff1a;13 代码&#xff1a;https://github.c…

A4-C四驱高防轮式巡检机器人

在当今数字化和智能化迅速发展的时代&#xff0c;旗晟智能带来了一款革命性的创新产品——A4-C四驱高防轮式巡检机器人。这款机器人以其卓越的性能和多功能性&#xff0c;为工业巡检领域带来了全新的解决方案。 一、产品亮点 1、四驱动力与高防护设计 四驱高防轮式巡检机器人…

ASUS/华硕枪神4 G532L G732L系列 原厂win10系统 工厂文件 带F12 ASUS Recovery恢复

华硕工厂文件恢复系统 &#xff0c;安装结束后带隐藏分区&#xff0c;一键恢复&#xff0c;以及机器所有驱动软件。 系统版本&#xff1a;Windows10 原厂系统下载网址&#xff1a;http://www.bioxt.cn 需准备一个20G以上u盘进行恢复 请注意&#xff1a;仅支持以上型号专用…

计算机应用数学--第一次作业

第一次作业计算题编程题 &#xff08;20分&#xff09; 第一次作业 计算题 &#xff08;20分&#xff09;求 E ( X ) E(X) E(X)&#xff0c; V a r ( X ) Var(X) Var(X) &#xff08;1&#xff09; X X X 服从 [ a , b ] [a,b] [a,b] 均匀分布。 &#xff08;2&#xff09;…

2024年智慧教育与社会科学国际会议 (ICSSS 2024)

2024年智慧教育与社会科学国际会议 (ICSSS 2024) 2024 International Conference on Smart Education and Social Sciences 【重要信息】 大会地点&#xff1a;北京 大会官网&#xff1a;http://www.icicsss.com 投稿邮箱&#xff1a;icicssssub-conf.com 【注意&#xff1a;稿…

Stable-diffusion-WebUI 的API调用(内含文生图和图生图实例)

前情提要 在之前尝试使用Diffusers库来进行stable-diffusion的接口调用以及各种插件功能实现&#xff0c;但发现diffusers库中各复杂功能的添加较为麻烦&#xff0c;而且难以实现对采样器的添加&#xff0c;safetensors格式模型的读取。在官网上找到了webui有专门的api接口&am…

1117 数字之王

solution 判断现有数字是否全为个位数 全为个位数&#xff0c;找出出现次数最多的数字&#xff0c;并首行输出最多出现次数&#xff0c;第二行输出所有出现该次数的数值不全为个位数 若当前位数值为0&#xff0c;无需处理若当前位数值非0&#xff0c;则每位立方相乘&#xff0…

10.x86游戏实战-汇编指令lea

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

Prometheus + Grafana 监控系统搭建使用指南-redis_exporter 安装与配置

Redis 接入 Prometheus 监控系统 系列文章目录 Prometheus 的安装部署Grafana的安装部署Linux服务器接入Prometheus监控-Node Exporter 安装指南Prometheus 接入SpringBoot微服务监控Mysql 接入 Prometheus RocketMQ 接入Prometheus 监控ElasticSearch 接入 PrometheusNacos …

vue使用axios获取信息的案例

List组件&#xff08;用来展示搜索的信息&#xff09; <template><div class"row"><!-- 列表数据 --><div class"card" v-for"user in info.users" :key"user.login" v-show"info.users.length">&l…

智慧校园-资产管理系统总体概述

智慧校园资产管理系统是面向教育机构设计的一体化数字平台&#xff0c;其核心目标在于通过先进的信息技术手段&#xff0c;全面优化校园内部的资产管理流程。该系统致力于提升资产管理的效率与透明度&#xff0c;同时降低成本并确保所有操作符合财务及审计规范&#xff0c;为校…