【数据结构】顺序表与ArrayList

news2024/12/28 23:48:57

作者主页:paper jie 的博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文录入于《JAVA数据结构》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将javaSE基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《算法详解》《C语言》《javaSE》等

内容分享:本期将会对数据结构中的顺序表进行讲解

目录

线性表

顺序表

简单顺序表的模拟实现

集合框架

ArrayList介绍

ArrayList的使用

ArrayList的构造

ArrayList的基本方法

ArrayList的遍历

ArrayList的扩容机制

画图分析

ArrayList的具体使用

顺序表ArrayList存储结构的优缺点


线性表

线性表就是有多个相同属性的数据元素的有限序列。线性表是一种在我们工作中广泛可以使用到的数据结构,常见的线性表:顺序表,链表,栈,队列……

线性表在逻辑上是线性结构,是一条连续的直线。但是它在物理结构上可可能不是连续的。线性表在物理上存储时,一般是以数组和链式结构的方式存储。

顺序表

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

简单顺序表的模拟实现

大家可以移步到我的Gitee上看代码,有点多,这里就不展示了:structure_code/java2023.9.12/src/mylist · 彭子杰/数据结构 - 码云 - 开源中国 (gitee.com)

集合框架

java集合框架,也称为容器,是定义在java.util包下的一组接口interfaces和其实现类class。它是要的作用是将多个元素element置于一个单元中,用于对这些元素进行快速,便捷的存储store,检索retrieve,管理manipulate,即平时我们说的增删查改。

类与接口总览:

ArrayList介绍

在java的集合框架(容器)中,ArrayList就是一个顺序表,它是一个普通的类,实现了List接口,框架如下:

注意:

ArrayList是以泛型方式实现的,使用时需要先实例化

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

ArrayList实现了cloneble接口,表明ArrayList是可以clone的

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

和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList

ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

ArrayList的使用

ArrayList的构造

public class Test {

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

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);
    } // 查找指定元素第一次出现的位置: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());
}

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

这里的迭代器是设计模式的一种。

ArrayList的扩容机制

 首选我们来看一段代码:

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

我们知道,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);
} r
eturn 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;
}

画图分析

【总结】

检查是否真正需要扩容,如果是g调用了row准备扩容

估计需要库容的大小

初步按照1.5倍的大小扩容

如果用户需要的大小超过1.5倍,则按照用户所需大小扩容

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

使用copyof进行扩容

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

顺序表ArrayList存储结构的优缺点

优点

不用为了表达清楚元素之间的关系而增加额外的存储空间。

可以快速地存取表中的任意一个位置的元素

缺点

在任位置删除插入元素的时间复杂度为O(N),所以需要移动大量的元素

当顺序表长度变化较大时,难以确定存储空间的容量。

容易造成存储空间的碎片,也就是浪费空间。

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

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

相关文章

2023研究生数学建模D题思路代码 区域双碳目标与路径规划研究

D题思路代码 区域双碳目标与路径规划研究 完整解题思路可看视频&#xff1a; 2023华为杯研赛D题区域双碳目标与路径规划研究&#xff08;附代码全保姆教程&#xff09;_哔哩哔哩_bilibili​www.bilibili.com/video/BV1Cm4y157CH/?spm_id_from333.999.0.0 问题一&#xff1a;…

将序列中的每一行重复扩展为指定数量的行Series.repeat()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 将序列中的每一行 重复扩展为指定数量的行 Series.repeat() [太阳]选择题 以下说法正确的是 import pandas as pd s1pd.Series([10, 25, 3]) s1.index [A, B, C] print(【显示】s1为&#xff…

超级好用的高效率记笔记软件

高效率的记录学习笔记&#xff0c;可以帮助我们日后进行知识的回顾、学习及分享&#xff0c;对于有记录学习笔记需求的学生来讲&#xff0c;在日常生活中找一款好用的记录学习笔记的非常有必要的&#xff0c;手机作为一款比较便携的工具&#xff0c;在手机上安装笔记类工具&…

家居行业如何借助AI营销数智化转型?《2023 家居行业AI营销第一课(重庆站)》给你答案

商务部将2023年定为“消费提振年”。作为仅次于汽车消费的家庭第二大消费支出&#xff0c;家居产业的高质量发展与扩大内需提振消费息息相关。随着今年利好政策不断发布&#xff0c;家居建材行业的市场环境及消费潜力得到大幅度改善。 随着ChatGPT等新技术的出现与消费需求升级…

安全基础 --- nodejs沙箱逃逸

nodejs沙箱逃逸 沙箱绕过原理&#xff1a;沙箱内部找到一个沙箱外部的对象&#xff0c;借助这个对象内的属性即可获得沙箱外的函数&#xff0c;进而绕过沙箱 前提&#xff1a;使用vm模块&#xff0c;实现沙箱逃逸环境。&#xff08;vm模式是nodejs中内置的模块&#xff0c;是no…

【腾讯云】打造未来智能应用的基石:腾讯混元大模型

写在前面&#xff1a;博主是一只经过实战开发历练后投身培训事业的“小山猪”&#xff0c;昵称取自动画片《狮子王》中的“彭彭”&#xff0c;总是以乐观、积极的心态对待周边的事物。本人的技术路线从Java全栈工程师一路奔向大数据开发、数据挖掘领域&#xff0c;如今终有小成…

vue-cli-service build 不同环境的配置

目录 &#x1f91c; 背景 &#x1f91c; vue-cli-service介绍 &#x1f91c; 环境变量和模式 &#x1f91c; 配置不同模式 &#x1f91c;index.html使用环境变量 &#x1f91c; 验证 &#x1f91c; 参考资料 &#x1f91c; 背景 在项目部署时&#xff0c;我们需要在测试…

如何通过文件自动备份软件进行自动化备份?

​为什么要使用文件自动备份软件 有一位做客户资料保管登记的朋友&#xff0c;每天会在电脑上录入很多新的客户资料&#xff0c;并需要进行相关维护。比如删掉一些取消合作的客户&#xff0c;或者添加一些备注等等。对于像他这种工作性质的人来说&#xff0c;很需要一个可以…

c++ this指针与空指针调用类方法以及常函数

一、this指针 说明 1、c的成员变量与成员内函数是分开存储 2、每一个非静态成员函数只会诞生一份函数实例&#xff0c;多个同类型的队形公用的是同一份成员函数的代码 3、this指向调用这一份成员函数代码的对象实例 4、this是一个隐藏的指向对象实例的一个指针,无需定义直接使…

使用Vue-cli构建spa项目及结构解析

一&#xff0c;Vue-cli是什么&#xff1f; 是一个官方发布的Vue脚手架工具&#xff0c;用于快速搭建Vue项目结构&#xff0c;提供了现代前端开发所需要的一些基础功能&#xff0c;例如&#xff1a;Webpack打包、ESLint语法检查、单元测试、自动化部署等等。同时&#xff0c;Vu…

百度SEO不稳定的原因及解决方法(百度SEO不稳定因素的5大包括)

百度SEO优化不稳定介绍&#xff1a;蘑菇号-www.mooogu.cn 随着百度SEO算法的不断变化和升级&#xff0c;许多网站的SEO排名经常出现不稳定的情况&#xff0c;这种情况在一定程度上影响了网站的流量和排名&#xff0c;导致网站的质量评分降低。因此&#xff0c;深入分析百度SEO…

ubuntu的root用户修改密码失败

解决如下&#xff1a; 查看文件属性是否有a或i lsattr /etc/group /etc/passwd /etc/shadow 移除a和i的属性权限 chattr -ai /etc/group /etc/passwd /etc/shadow 再次使用passwd进行修改密码&#xff0c;就成功了

时序预测 | MATLAB实现NGO-LSTM北方苍鹰算法优化长短期记忆网络时间序列预测

时序预测 | MATLAB实现NGO-LSTM北方苍鹰算法优化长短期记忆网络时间序列预测 目录 时序预测 | MATLAB实现NGO-LSTM北方苍鹰算法优化长短期记忆网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现NGO-LSTM北方苍鹰算法优化长短期记忆网络时间序列预…

排序算法-----计数排序

目录 前言&#xff1a; 计数排序 1.算法描述 2. 基本思想 3.实现逻辑 4.示例剖析 5.动图演示 代码实现 1.C/C代码 2.Python代码 算法分析 时间复杂度 空间复杂度 稳定性 局限性 前言&#xff1a; 有没有一种排序时间复杂度为直线正比的排序算法呢&#xff1f;有…

贸易战的影响:跨境电商的“黑洞”风险与机遇

当今全球贸易局势充满了不确定性和动荡。贸易战的阴云笼罩下&#xff0c;跨境电商企业面临着前所未有的挑战&#xff0c;但与此同时&#xff0c;也蕴藏着巨大的机遇。本文将深入探讨贸易战对跨境电商的影响&#xff0c;以及企业在这个新现实中如何应对风险并寻找机遇。 贸易战的…

以京东平台为例写一份电商平台API接口文档

公共参数 请求地址: 申请调用KEY地址 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_shop等]cacheSt…

Microsoft edge 设置百度首页

1. 新建页下载插件&#xff1a;New Tab Redirect 怎样将浏览器启动页和新标签页设置为特定的网页-百度经验 (baidu.com) 2. 首页设置百度页&#xff1a; 打开联想电脑管家

Talk | ICCV’23 清华赵天辰:Ada3D-基于动态推理的3D感知模型压缩及软硬件协同优化

​本期为TechBeat人工智能社区第533期线上Talk&#xff01; 北京时间9月21日(周四)20:00&#xff0c;清华大学博士生—赵天辰的Talk已准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “Ada3D-基于动态推理的3D感知模型压缩及软硬件协同优化”&#xff0c;他…

Go面试题:锁的实现原理sync-mutex篇

在Go中&#xff0c;主要实现了两种锁&#xff1a;sync.Mutex(互斥锁) 以及 sync.RWMutex(读写锁)。 本篇主要给大家介绍sync.Mutex的使用和实现原理。 文章目录 为什么需要锁在Go中对于并发程序进行公共资源的访问的限制最常用的就是互斥锁&#xff08;sync.mutex&#xff09…

理清SpringBoot CURD处理逻辑、顺序

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 理清SpringBoot CURD处理逻辑、顺序 Controller&#xff08;控制器&#xff09;&#xff1a; 控制器接收来自客户端的请求&#xff0c;并负责处理请求的路由和参数解析…