Collection与数据结构 顺序表与ArrayList

news2024/9/20 21:46:22

1. 线性表

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

2. 顺序表

顺序表是一段物理空间连续的线性表,在底层一般使用数组来实现,在数组的基础上完成增删查改.下面是顺序表的一些接口.

2.1 接口

public interface Ilist {
    void add(int data);//为顺序表的尾部增加元素
    void add(int data ,int pos);//为指定位置添加元素
    void display();//打印顺序表
    int size ();//检测顺序表中元素的个数
    boolean contains(int toFind);//检测顺序表中是否包含该元素
    int indexOf(int toFind);//返回所要寻找第一个元素的下标
    int get(int index);//获取指定下标的元素
    void set(int index,int val);//把指定下标的元素指定为指定元素
    void remove(int toRomve);//移除第一个指定的元素
    void clear();//清空顺序表
}

下面我们来实现这些接口:

import java.util.Arrays;

/**
 * 顺序表底层是用数组来实现的
 */
public class MyArrayList implements Ilist {
    private int[] elem;
    private int size;//记录有效数据
    public static final int DEFAULT_CAPACITY = 5;//默认容量
    private boolean isFull(){
        return size == elem.length;//判断顺序表的容量是否为满
    }
    private void checkPos(int pos){
        if (pos < 0 || pos >= size){
            throw new PosException("pos is false");//判断插入位置是否合法
        }
    }
    private boolean isEmpty(){
        return this.size == 0;
    }

    public MyArrayList() {
        this.elem = new int[DEFAULT_CAPACITY];//默认容量为5
        this.size = 0;
    }//无参数的构造方法
    public void add(int data){//在末尾的位置添加元素
        if (isFull()){
            elem = Arrays.copyOf(elem,elem.length*2);//扩容
        }
        elem [size] = data;
        size++;
    }
    public void add(int data ,int pos){//在指定位置添加元素
        checkPos(pos);
        if (isFull()){
            elem = Arrays.copyOf(elem,elem.length*2);//扩容
        }
        for (int i = size-1; i >= pos ; i--) {//数组整体后移
            elem [i+1] = elem [i];
        }
        elem[pos] = data;
        size++;
    }
    public void display(){//打印顺序表
        System.out.print("["+" ");
        for (int i = 0; i < size; i++) {//打印有效元素
            System.out.print(elem[i]+" ");
        }
        System.out.print("]");
    }
    public int size (){//返回当前顺序表大小
        return this.size;
    }
    public boolean contains(int toFind){
        for (int i = 0; i < size; i++) {//在这里不可以用elem.length,后面的扩容之后未赋值
            if(elem[i] == toFind){
                return true;
            }
        }
        return false;
    }
    public int indexOf(int toFind){//返回要找的元素第一个返回的下标
        for (int i = 0; i < size; i++) {//在这里不可以用elem.length,后面的扩容之后未赋值
            if(elem[i] == toFind){
                return i;
            }
        }
        return -1;
    }
    public int get(int index){//获取index位置的值
        checkPos(index);
        if (isEmpty()){//存在默认容量5,若没有此方法,可能会在未初始化的位置上直接获取元素,获取成功
            //但是为0,不符合实际
            throw new EmptyException("array is empty");
        }
        return elem[index];
    }
    public void set(int index,int val){//把index位置的值改为val
        checkPos(index);
        if (isEmpty()){//存在默认容量5,若没有此方法,可能会在未初始化的位置上直接添加元素,
            //添加成功,但是不符合实际
            throw new EmptyException("array is empty");
        }
        elem[index] = val;
    }
    public void remove(int toRomve){//移除第一次出现的元素
        if (isEmpty()){
            throw new EmptyException("array is empty");
        }
        int index = indexOf(toRomve);//先找到下标的位置
        for (int i = index+1; i < size; i++) {
            elem[i-1] = elem[i];
        }
        elem[size-1] = 0;
        size --;
    }
    public void clear(){
        size = 0;
    }
}

```java
public class EmptyException extends NullPointerException{
    public EmptyException(String s) {
        super(s);
    }
}

public class PosException extends ArrayIndexOutOfBoundsException{
    public PosException(String s) {
        super(s);
    }
}

下面通过一些测试用例;来测试:

public class Main {
    public static void main(String[] args) {
        MyArrayList list = new MyArrayList();
        list.add(0);
        list.add(1);
        list.add(3);
        list.add(4);
        list.add(2,2);
        list.add(5);
        list.display();
        System.out.println(list.size());
        list.remove(2);
        list.display();
        System.out.println(list.size());
    }
}

在这里插入图片描述

3.ArrayList简介

在这里插入图片描述
[说明]

  1. ArrayList是以泛型的方式实现的,使用时必须先实例化.
  2. ArrayList的底层是一段连续的存储空间,并且可以动态扩容,是一个动态类型的顺序表.

4.ArrayList的使用

4.1 ArrayList的构造方法

方法解释
public ArrayList()无参构造方法
public ArrayList(int initialCapacity)指定顺序表初始容量
public ArrayList(Collection<? extends E> c)利用Collection中的容器来构造

关于第三个构造方法,不太好理解,我们下面来解释一下:ArrayList已经传入了泛型的参数,就是E,这里用来构造ArrayList的Collection类中的元素必须是E的子类.

ArrayList<Integer> list = new ArrayList<>();
ArrayList<Integer> list1 = new ArrayList<>(list);
ArrayList<Number> list2 = new ArrayList<>(list);
ArrayList<Integer> list3 = new ArrayList<>(10);

4.2 ArrayList常见操作

方法解释
boolean add(E e)在尾部添加元素
void add(int index,E element)在指定位置添加元素
boolean addAll(Collection<? extends E> c)把c中的元素全部添加到顺序表尾部
E remove(int index)移除指定位置的元素
boolean remove(Object o)移除遇到的第一个元素o
E get(int index)获取指定位置的元素
E set(int index,E element)把指定位置的元素设置为指定的值
void clear()清空顺序表
boolean contains(Object o)检测顺序表中是否包含o
int indexOf(Object o)返回第一个指定元素所在的下标
int lastIndexOf(Object o)从后向前找,返回第一个元素所在的下标
List subList(int fromIndex,int toIndex)截取指定范围的字符串,左闭右开

在这里说明一下两个remove方法的区别,避免混淆,第一个remove方法时移除指定位置的元素,传入的元素类型为int类型的数据,而第二个remove方法移除的是第一个遇到的元素,这里传入的参数类型是和顺序表泛型相同的类型,当一个顺序表中存储的是Integer类型的数据的时候,要注意区分下标和元素.
下面对上述方法进行演示:

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

4.3 ArrayList的遍历

ArrayList有四种遍历方式,一种是通过sout直接输出,一种是for-i,一种是for-each,一种是使用迭代器.

import java.util.ArrayList;
import java.util.Iterator;
public class TestArrayList {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        //通过sout去遍历ArrayList
        System.out.println(list);
        //通过fori遍历
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i)+" ");
        }
        System.out.println();
        //通过foreach遍历
        for (int x:list) {
            System.out.print(x+" ");
        }
        System.out.println();
        //通过迭代器遍历
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.print(iterator.next()+" ");
        }
        System.out.println();
     }
}

4.4 ArrayList扩容机制

ArrayList是动态的顺序表,在顺序表的容量不够的时候会自动扩容,下面是底层代码对ArrayList的扩容机制.

	public boolean add(E e) {
        modCount++;//底层是C/C++代码
        add(e, elementData, size);//调用另一个重载的add方法,指定添加容积
        return true;
    }
	private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)//容器满的时候需要扩容
            elementData = grow();//调用grow方法扩容
        elementData[s] = e;
        size = s + 1;
    }
	private Object[] grow() {
        return grow(size + 1);//最小容积是size+1,就是指定的添加容积+1
    }
    private Object[] grow(int minCapacity) {//传入指定的最小容积
        int oldCapacity = elementData.length;
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            int newCapacity = ArraysSupport.newLength(oldCapacity,//对数组扩容
                    minCapacity - oldCapacity, /* minimum growth */    //计算原容量和最小容积的差值
                    oldCapacity >> 1  //原容量的一半         /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);//正式扩容
        } else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }
	public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
        // preconditions not checked because of inlining
        // assert oldLength >= 0
        // assert minGrowth > 0
        int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
        //若pre大,1.5被扩容,若是min大,直接加上指定的最小容积
        if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
            return prefLength;
        } else {
            // put code cold in a separate method
            return hugeLength(oldLength, minGrowth);
        }
    }

[总结]

  1. 预估要扩容的大小
  • 初步预估按照1.5倍扩容.
  • 如果用户所需大小预估超过1.5,则按照用户所需大小扩容.
  1. 使用copyOf扩容.

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

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

相关文章

libVLC 设置滤镜

在图像和视频处理中&#xff0c;滤镜是一种用于修改图像或视频帧外观的软件工具。滤镜可以通过各种方式改变图像的像素数据&#xff0c;以达到不同的视觉效果。以下是一些常见的滤镜类型&#xff1a; 颜色调整&#xff1a;这些滤镜可以改变图像的亮度、对比度、饱和度、色调等颜…

中科数安 || 设计公司的图档、文件资料、各类设计图纸怎么防止外泄,自动智能透明加密管理软件系统

#文件防泄密软件# 中科数安为设计公司提供了一整套针对图档、文件资料以及各类设计图纸的保密解决方案&#xff0c;帮助企业在多个层面上防止此类重要信息的外泄。 设计行业&#xff0c;部门 || 图档防泄密软件 PC地址&#xff1a; www.weaem.com 以下是中科数安可能采取…

搭建PHP本地开发环境:看这一篇就够了

什么是PHP本地开发环境 PHP本地开发环境是指在个人计算机上模拟的服务器环境&#xff0c;这使得开发者能够在没有网络连接的情况下也能开发、测试和调试PHP应用程序。就像在你的电脑里装个小“服务器”&#xff0c;即使没网也能搞定PHP程序的开发和修修补补。这就是PHP本地开发…

值迭代和策略迭代【强化学习】

强化学习笔记 主要基于b站西湖大学赵世钰老师的【强化学习的数学原理】课程&#xff0c;个人觉得赵老师的课件深入浅出&#xff0c;很适合入门. 第一章 强化学习基本概念 第二章 贝尔曼方程 第三章 贝尔曼最优方程 第四章 值迭代和策略迭代 文章目录 强化学习笔记一、Value It…

springboot企业级抽奖项目业务三(活动模块)

梅开三度 开发流程 该业务基于rouyi生成好了mapper和service的代码&#xff0c;现在需要在controller层写接口 实际操作流程&#xff1a; 看接口文档一>controller里定义函数一>看给出的工具类一>补全controller里的函数一>运行测试 接口文档 在用户模块用户…

Cisco firepower 2140 run ASA and config failover

1 背景 here we got 2 cisco firepower 2140 hardware appliance we’re planning to run ASA on it. and config failover for Primary Unit and Secondary Unit 现场2台Cisco firepower 2140防火墙&#xff0c; 运行ASA模式&#xff0c; 双机组HA&#xff0c;心跳线使用E1/1…

爬虫实践(1)

这一篇只提登录模拟&#xff0c;主要介绍chrome开发者窗口的使用&#xff0c;实际上相关接口调用都是用到cookie&#xff0c;需要再加一篇从token到cookie&#xff0c;以保证实践的完整性 以migu登录为例&#xff0c;分析其登录过程&#xff0c;之后可以使用任意语言模拟登录&…

如何利用FLUENT计算流体力学方法解决大气与环境领域流动问题

ANSYS FLUENT是目前全球领先的商用CFD 软件&#xff0c;市场占有率达70%左右&#xff0c;是工程师和研究者不可多得的有力工具。由于采用了多种求解方法和多重网格加速收敛技术&#xff0c;因而FLUENT能达到最佳的收敛速度和求解精度。灵活的非结构化网格和基于解的自适应网格技…

设置MATLAB三维绘图的视角

MATLAB三维绘图plot3在生成绘图后&#xff0c;默认显示视角是斜着的&#xff1a; 使用view(2)命令可以使其转成XoY平面&#xff08;从上往下看的视角&#xff09;&#xff1a;

【第二部分--Python之基础】02

二、运算符与程序流程控制 1、运算符 1.1 算术运算符 算术运算符用于组织整数类型和浮点类型的数据&#xff0c;有一元运算符和二元运算符之分。 一元算术运算符有两个&#xff1a;&#xff08;正号&#xff09;和-&#xff08;负号&#xff09;&#xff0c;例如&#xff1…

自动驾驶-如何进行多传感器的融合

自动驾驶-如何进行多传感器的融合 附赠自动驾驶学习资料和量产经验&#xff1a;链接 引言 自动驾驶中主要使用的感知传感器是摄像头和激光雷达&#xff0c;这两种模态的数据都可以进行目标检测和语义分割并用于自动驾驶中&#xff0c;但是如果只使用单一的传感器进行上述工作…

【Python】enumerate函数的使用方法,小白一看就懂

enumerate函数的使用方法&#xff1a; season[‘a’,‘b’,‘c’,‘d’] for i in enumerate(season): print(i) season[‘a’,‘b’,‘c’,‘d’] for i,eliment in enumerate(season): print(i,eliment) 输出结果为&#xff1a; 练习题&#xff1a; 2.给出10个学生姓名…

国内ip地址随意更换的潜在风险和策略

在数字化时代&#xff0c;IP地址是互联网通信的基础&#xff0c;而国内IP地址的随意更换可能带来一系列安全风险和问题。虎观代理小二将探讨国内IP地址随意更换的潜在影响以及如何有效应对这一挑战。 1.什么是国内IP地址&#xff1f; 国内IP地址是指在国内分配和使用的IP地址&…

【漏洞复现】用友U8C任意文件读取漏洞

声明&#xff1a;亲爱的读者&#xff0c;我们诚挚地提醒您&#xff0c;Aniya网络安全的技术文章仅供个人研究学习参考。任何因传播或利用本实验室提供的信息而造成的直接或间接后果及损失&#xff0c;均由使用者自行承担责任。Aniya网络安全及作者对此概不负责。如有侵权&#…

ChatGPT 对 ELT的理解

本文主要内容来自 ChatGPT 4.0 到底什么是 ETL&#xff1f;在数据库内部&#xff0c;把数据从 ODS 层加工成 DWD&#xff0c;再加工成 DWS&#xff0c;这个过程和 ETL 的关系是什么&#xff1f;带着这些问题&#xff0c;我问了一下 ChatGPT&#xff0c;总结如下。 数据在两个数…

工厂能耗管控物联网解决方案

工厂能耗管控物联网解决方案 工厂能耗管控物联网解决方案是一种创新的、基于先进技术手段的能源管理系统&#xff0c;它深度融合了物联网&#xff08;IoT&#xff09;、云计算、大数据分析以及人工智能等前沿科技&#xff0c;以实现对工业生产过程中能源消耗的实时监测、精确计…

小学科学期刊投稿邮箱论文发表

《小学科学》是由国家新闻出版总署批准的教育理论类半月刊&#xff0c;由长春出版传媒集团有限责任公司主管主办&#xff0c;旨在为广大一线科学教师、教研员和其他教育工作者提供一个展示传播、交流、研讨科学教育及教研成果的平台&#xff0c;促进小学科学教育工作者的沟通与…

智能楼宇3D可视化解决方案

什么是智能楼宇? 智能楼宇是为提高楼宇的使用合理性与效率,配置合适的建筑环境系统与楼宇自动化系统、办公自动化与管理信息系统以及先进的通信系统,并通过结构化综合布线系统集成为智能化系统的大楼。 面临的问题 信息孤岛,无法统一管理 各个子系统独立工作、独立管理,…

达梦数据库自动备份(全库)+还原(全库) 控制台

一 前提 1.安装达梦数据库DB8(请参照以前文章) 我的数据库安装目录是 /app/dmDB8 2.已创建实例 (请参照上一篇文章) 二 准备测试数据 三 自动备份步骤 1.开启归档模式 开启DM管理工具管理控制台 弹不出来工具的 输入命令 xhost 第一步 将服务器转换为配置状态 右键-&g…

冒泡排序 快速排序 归并排序 其他排序

书接上回.. 目录 2.3 交换排序 2.3.1冒泡排序 2.3.2 快速排序 快速排序的优化: 快速排序非递归 2.4 归并排序 基本思想 归并排序非递归 海量数据的排序问题 排序算法时间空间复杂度和稳定性总结 四. 其他非基于比较排序 (了解) 2.3 交换排序 基本思想&#xff1a;…