【数据结构】_3.List接口实现类ArrayList与线性表

目录

1.List接口

1.1 List接口的集合关系网络

1.2 List的使用

2. ArrayList与顺序表

2.1 线性表

2.2 顺序表

2.3 ArrayList

2.3.1 ArrayList的集合关系网络

2.3.2  ArrayList的使用

2.3.2.1 ArrayList的构造方法

2.3.2.2 ArrayList的扩容机制逻辑示图如下:

2.3.2.3 常用方法

2.3.2.4 ArrayList的遍历

2.3.3 ArrayList的具体使用

2.3.3.1 字符串处理问题

2.3.3.2 杨辉三角

2.3.3.3 简单的洗牌算法

 2.3.4 ArrayList特点


1.List接口

1.1 List接口的集合关系网络

在集合中,List是一个接口,继承自Collection,Collection也是一个接口;

在数据结构中,List是一个线性表,即n个具有想同类型元素的有限序列,在该序列上可以执行增删查改等操作;

1.2 List的使用

List是一个接口,并不能直接用来实例化,如果要使用就必须实例化List的实现类,在集合框架中,ArrayList和LinkedList都实现了List接口;

接下来将依次展示List的实现类使用方法,本篇为ArrayList;

2. ArrayList与顺序表

2.1 线性表

线性表是n个具有相同特性的数据元素的有限序列,线性表是一种在实际中广泛使用的数据结构,常见的线性表有:顺序表、链表、栈、队列等等;

线性表在逻辑上是线性结构,即连续的一条直线,但在物理结构上不一定连续。

线性表在物理存储时通常以数组和链式的形式存储;

2.2 顺序表

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

下面展示顺序表常用接口的模拟实现:

(1)包类示图:

 (2)MyArrayList:

package TestMyArrayList;
import java.util.Arrays;
public class MyArrayList {public int[] elem;public int useSize;     // 记录顺序表存储的有效数据个数public static final int DEFAULT_SIZE=10;public MyArrayList(){this.elem = new int[DEFAULT_SIZE];}// 成员方法1:打印顺序表public void display(){for(int i=0;i<this.useSize;i++){System.out.print(this.elem[i]+" ");}}// 成员方法2:获取顺序表长度public int size(){return this.useSize;}// 成员方法3:判定是否包含某个元素public boolean contains(int toFind){for(int i=0;i<this.useSize;i++){if(elem[i]==toFind){return true;}}return false;}// 成员方法4:查找某个元素对应的位置public int indexOf(int toFind){for(int i=0;i<this.useSize;i++){if(elem[i]==toFind){return i;}}return -1;   // 数组没有负数下标}// 成员方法5:新增元素(默认放在数组最后位置)public void add(int data){// 判满if(this.isFull()){//扩容this.resize();}elem[this.useSize]=data;this.useSize++;}// 成员方法6:判满public boolean isFull(){// 写法1:
//        if(this.useSize==this.elem.length){
//            return true;
//        }
//        return false;// 写法2:return this.useSize==this.elem.length;}// 成员方法7:扩容private void resize(){ // 扩容只针对当前顺序表,可以进行封装this.elem= Arrays.copyOf(this.elem,2*this.elem.length);}// 成员方法8:在pos位置新增元素public void add(int pos, int data){// 判pos是否合法checkAddIndex(pos);// 判满if(isFull()){this.resize();}for(int i=useSize-1;i>=pos;i--){elem[i+1]=elem[i];}this.elem[pos]=data;this.useSize++;}// 成员方法9:判插入数据时,pos是否合法private void checkAddIndex(int pos){if(pos<0||pos>this.useSize){throw new AddIndexOutOfException("pos is illegal!");}}// 成员方法10:获取pos位置的元素public int get(int pos){checkAddIndex(pos);return this.elem[pos];}// 成员方法11:判获取数据时,pos是否合法private void checkGetIndex(int pos){if(pos<0||pos>=this.useSize){throw new AddIndexOutOfException("pos is illegal!");}}// 成员方法12:将pos位置的数据设置为valuepublic void set(int pos, int value){checkGetIndex(pos);this.elem[pos]=value;}// 成员方法13:删除第一次出现的关键字keypublic boolean remove(int toRemove){int index=indexOf(toRemove);if(index==-1){System.out.println("data is non existent!");return false;}for(int i=index;i<this.useSize-1;i++){// useSize-1可保证不越界elem[i]=elem[i+1];}this.useSize--;this.elem[this.useSize]=0; // 若是引用类型则置为nullreturn true;}// 成员方法14:清空顺序表public void clear(){for(int i=0;i<this.useSize;i++){this.elem[i]=0;}this.useSize=0;}
}

(3)GetIndexOutOfException

package TestMyArrayList;public class GetIndexOutOfException extends RuntimeException{public GetIndexOutOfException(){}public GetIndexOutOfException(String message){super(message);}
}

(4)AddIndexOutOfException

package TestMyArrayList;public class AddIndexOutOfException extends RuntimeException{public AddIndexOutOfException(){}public AddIndexOutOfException(String message){super(message);}
}

2.3 ArrayList

2.3.1 ArrayList的集合关系网络

说明:

(1)ArrayList是以泛型方式实现的,使用时必须实例化;

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

(3)ArrayList实现了Clone接口,表明ArrayList是可以clone的;

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

(对象->字符串:序列化;字符串->对象:反序列化)

(5)相比于Vector,ArrayList不是线程安全的,在单线程下可使用,在多线程中可以选择Vector或者CopyOnWriteArrayList;

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

2.3.2  ArrayList的使用

2.3.2.1 ArrayList的构造方法

ArrayList的构造方法有以下三种:

示例代码如下:

(1)构造方法1:(无参构造器)

        // 构造方法1:ArrayList<Integer> arrayList1 = new ArrayList<>();arrayList1.add(97);arrayList1.add(8);arrayList1.add(5);System.out.println(arrayList1);

输出结果为:

(2)构造方法2:(带有初始容量的构造方法)

        // 构造方法2:ArrayList<Integer> arrayList2 = new ArrayList<>(20);arrayList2.add(1997);arrayList2.add(85);arrayList2.add(25);System.out.println(arrayList2);

 输出结果为:

(3)构造方法3:

        // 构造方法3:LinkedList<Integer> list = new LinkedList<>();list.add(1);list.add(2);list.add(3);ArrayList<Integer> arrayList3 = new ArrayList<>(list);ArrayList<Number> arrayList4 = new ArrayList<>(list);System.out.println(arrayList3);System.out.println(arrayList4);

输出结果为:

第三种构造方法的含义为:将另外一个实现了Collection接口的具体类作为构造ArrayList的具体参数,

且满足:该具体类的泛型参数是ArrayList实例化对象的泛型参数本身或其子类,

即可将该类中的所有元素添加至ArrayList实例化的该对象中来;

2.3.2.2 ArrayList的扩容机制逻辑示图如下:

简而言之:

在实例化ArrayList对象进行new操作时,其实并没有为该对象分配内存,但在第一次进行add时,会调用grow方法为其分配长度为10的内存大小;

且扩容方式为1.5倍扩容法;

2.3.2.3 常用方法

方法解释
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<E> subList(int fromIndex,int toIndex)截取部分list

方法示例:

(1)E remove(int index) 与 boolean remove(Object o):

        ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(2);arrayList.add(3);System.out.println(arrayList);arrayList.add(0,1);System.out.println(arrayList);arrayList.remove(2);System.out.println(arrayList);arrayList.remove(new Integer(1));System.out.println(arrayList);

输出结果为:

 (2)List<E> subList(int fromIndex,int toIndex):(注意接收类型为List而非ArrayList

        ArrayList<Integer> arrayList1 = new ArrayList<>();for(int i=0;i<10;i++){arrayList1.add(i*2+1);}System.out.println(arrayList1);List<Integer> arrayList2 = arrayList1.subList(3,6);System.out.println(arrayList2);

输出结果为:

注:原ArrayList对象arrayList1和截取的子串arrayList2共用一个elemData数组,修改元素时二者相互影响

        ArrayList<Integer> arrayList1 = new ArrayList<>();for(int i=0;i<10;i++){arrayList1.add(i*2+1);}System.out.println("Before modify: ");System.out.println("arrayList1: "+arrayList1);List<Integer> arrayList2 = arrayList1.subList(3,6);System.out.println("arrayList2: "+arrayList2);arrayList2.set(0,999);System.out.println("After modify: ");System.out.println("arrayList1: "+arrayList1);System.out.println("arrayList2: "+arrayList2);

输出结果为:

2.3.2.4 ArrayList的遍历

方法1:直接输出:

ArrayList类并没有重写toString方法,其父类AbstractList也没有重写toString方法,但是List接口有toString方法,故而可以直接使用System.out.println()方法输出ArrayList对象;

上文代码已有示例,此处不再赘述;

方法2:for循环:

        ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1997);arrayList.add(8);arrayList.add(5);arrayList.add(25);for(int i=0;i<arrayList.size();i++){System.out.print(arrayList.get(i)+"  ");}

输出结果为:

  

方法:3:for-each:

        ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1997);arrayList.add(8);arrayList.add(5);arrayList.add(25);for(Integer x:arrayList){System.out.print(x+"  ");}

输出结果为:

  

方法4:迭代器:

迭代器方法源码如下:

试运行以下代码:

        ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1997);arrayList.add(8);arrayList.add(5);arrayList.add(25);ListIterator<Integer> it = arrayList.listIterator();while(it.hasNext()){System.out.print(it.next()+"  ");// 打印it的同时令it前行一步}

输出结果为:

2.3.3 ArrayList的具体使用

2.3.3.1 字符串处理问题

题目描述:现有字符串s1:"Welcome to java"和字符串s2:"come",试将s1中包含的s2的字符删去后的结果;

思路:遍历字符串s1,当s2不包含s1当前的字符则添加至一个ArrayList对象中,输出该对象结果即可;

代码如下:

    public static void main(String[] args) {List<Character> list = new ArrayList<>();String s1 = "Welcome to java";String s2 = "come";for(int i=0;i<s1.length();i++){char ch = s1.charAt(i);if(!s2.contains(ch+"")){// 字符串的包含操作参数为CharSequence,String类也实现了CharSequence接口// 故而需要将获取到的s1中的字符处理为字符串list.add(ch);}}for(Character x:list){System.out.print(x);}}

输出结果为:

2.3.3.2 杨辉三角

题目描述:

题目链接如下:118. 杨辉三角 - 力扣(LeetCode)

代码如下:

class Solution {public List<List<Integer>> generate(int numRows) {//List嵌套List即二维数组List<List<Integer>> ret = new ArrayList<>();List<Integer> row = new ArrayList<>();row.add(1);   // 初始化第一行(只有一个元素,为1)ret.add(row); // 创建二维数组for(int i=1;i<numRows;i++){List<Integer> previousRow = ret.get(i-1);  //获取上一行元素List<Integer> currentRow = new ArrayList<>();currentRow.add(1);  // 每一行第一个元素为1// 每一行非两端位置元素赋值for(int j=1;j<i;j++){int x = previousRow.get(j)+previousRow.get(j-1);currentRow.add(x);}currentRow.add(1);  // 每一行最后一个元素也为1ret.add(currentRow);}return ret;}
}

 通过用例测试,参考输出示例如下:

2.3.3.3 简单的洗牌算法

(1)创建包类关系如下:

(2)Poker类:

package TestDemo1;
public class Poker {private String suit; // 花色private int rank;    //数字public Poker(String suit, int rank) {this.suit = suit;this.rank = rank;}public String getSuit() {return suit;}public void setSuit(String suit) {this.suit = suit;}public int getRank() {return rank;}public void setRank(int rank) {this.rank = rank;}@Overridepublic String toString() {return "{" + suit+" "+ rank+ "}";}
}

(3) Game类:

package TestDemo1;import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class Game {private static final String[] suits = {"♥","♣","♦","♠"};public List<Poker> buyPoker(){List<Poker> pokers = new ArrayList<>();for(int i=0;i<4;i++){for(int j=1;j<=13;j++){String suit = suits[i]; // 花色int rank = j;    // 数字Poker poker = new Poker(suit,j);pokers.add(poker);}}return pokers;}// 洗牌public void shuffle(List<Poker> pokers){for(int i=pokers.size()-1; i>0;i--){Random random = new Random();int index = random.nextInt(i);Swap(pokers,i,index);}}private void Swap(List<Poker> pokers,int i,int j){Poker tmp = pokers.get(i);pokers.set(i,pokers.get(j));pokers.set(j,tmp);}// 揭牌:三个人轮流揭5张牌// 每次删除pokers的0下标的元素,并依次添加至3个ArrayList对象中public List<List<Poker>> game(List<Poker> pokers){// 创建玩家ListList<List<Poker>> players = new ArrayList<>();List<Poker> player1 = new ArrayList<>();List<Poker> player2 = new ArrayList<>();List<Poker> player3 = new ArrayList<>();players.add(player1);players.add(player2);players.add(player3);for(int i=0;i<5;i++){   // 控制揭牌揭5轮for(int j=0;j<3;j++){    // 控制每个玩家每次揭牌揭一张Poker currentPoker = pokers.remove(0);// ArrayList的remove方法会将查找下标对应的元素返回players.get(j).add(currentPoker);}}return players;}
}

(4)Test类:

package TestDemo1;
import java.util.List;
public class Test {public static void main(String[] args) {Game game = new Game();List<Poker> pokers = game.buyPoker();int count=1;for(Poker x:pokers){System.out.print(x+"  ");count++;if(count%10==0){System.out.println();}}game.shuffle(pokers);System.out.println();System.out.println("------------------------------------------------------------------");System.out.println("洗牌:");count=1;for(Poker x:pokers){System.out.print(x+" ");count++;if(count%10==0){System.out.println();}}System.out.println();System.out.println("------------------------------------------------------------------");System.out.println("揭牌:");List<List<Poker>> players = game.game(pokers);for(int i=0;i<players.size();i++){System.out.println("第"+(i+1)+"位玩家牌面:");System.out.println(players.get(i));}System.out.println("------------------------------------------------------------------");System.out.println("余牌牌面:");count=1;for(Poker x:pokers){System.out.print(x+" ");count++;if(count%10==0){System.out.println();}}}
}

 (5)输出结果为:

 注:ArrayList类的remove方法源码:

可见其逻辑为:删除哪个下标的值,就将该下标的元素作为返回值进行返回;

 2.3.4 ArrayList特点

优点:(1)当给定下标时,ArrayList的查找速度非常快。故而ArrayList适合给定下标的查找,复杂度为O(1);

缺点:(1)任意位置插入或删除元素时,需要大量挪动元素,故而ArrayList不适合应用于任意位置插入和删除较为频繁的场景;

(2)每次扩容时也面临着资源浪费的问题,同时申请新空间,拷贝数据再释放旧空间也有不小的消耗;

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

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

相关文章

【江西省研究生数学建模竞赛】第一题 蒸汽发生器倒U型管内液体流动 70页论文及MATLAB代码

【江西省研究生数学建模竞赛】题目之一 蒸汽发生器倒U型管内液体流动 70页论文及MATLAB代码 相关链接 【江西省研究生数学建模竞赛】第一题 蒸汽发生器倒U型管内液体流动 70页论文及MATLAB代码 【江西省研究生数学建模竞赛】第一题 蒸汽发生器倒U型管内液体流动 70页论文及MA…

Thread-local storage is not supported for the current target

xcode编译时遇到上述报错&#xff0c;解决办法&#xff1a;调整最低系统版本配置

BUFG/BUFGCE/BUFH/BUFHCE

对BUFG/BUFGCE/BUFH/BUFHCE简单了解。 下图为 7 系列 FPGA 时钟架构图&#xff1a; BUFG 全局时钟缓冲器。它的输入是IBUFG的输出&#xff0c;BUFG的输出到达FPGA内部的IOB、CLB、选择性块RAM的时钟延迟和抖动最小。BUFG连接的是芯片中的专用时钟资源&#xff0c;能减少信号…

【C】字符串函数和内存函数的介绍

库函数&#xff08;这些函数都在头文件string.h中&#xff09; 字符串函数求字符串长度strlen 长度不受限的字符串函数strcpystrcmpstrcat 长度受限的字符串函数strncpystrncmpstrncat 字符串查找strstrstrtok 错误信息报告strerror 字符操作字符分类函数字符转换函数 内存函数…

API开发,机器人api二次开发

由于自身在机器人方面滚爬多年&#xff0c;尝试了很多次&#xff0c;选择了一个信任的工具 可以给有需要的朋友们借鉴一下 开发起来很方便&#xff0c;技术也已经挺成熟的了 贴一点简单的给大家看下呢 测试文档&#xff1a;https://www.wkteam.cn/ 简要描述&#xff1a; …

.net6中WPF的串口通信和USB通信

之前写过串口通信&#xff0c;不过是winform的。 c#使用串口进行通信_c# 串口通信_故里2130的博客-CSDN博客 今天说一下&#xff0c;.net6中wpf的串口通信和USB通信&#xff0c;在工控行业中&#xff0c;这2种的方式非常多&#xff0c;还有网口通信&#xff0c;它们都是用来和…

微信小程序下拉选择

微信小程序中下拉框选择一般的交互方式有以下两种 直接下拉选择点击选择框后&#xff0c;弹出浮层进行选择 下边分别介绍两种方式的实现。在微信小程序中&#xff0c;这两种实现都需要修改三个文件 js 文件&#xff1a;下拉选择逻辑的具体实现 wxml 文件&#xff1a;下拉组件…

如何用Jmeter提取和引用Token

1.执行获取token接口 在结果树这里&#xff0c;使用$符号提取token值。 $根节点&#xff0c;$.data.token表示提取根节点下的data节点下的token节点的值。 2.使用json提取器&#xff0c;提取token 变量路径就是把在结果树提取的路径写上。 3.使用BeanShell取样器或者BeanShe…

用Python采集电商平台商品数据进行可视化分析

目录标题 前言环境使用:模块使用:基本流程思路:代码展示获取数据扩展知识数据可视化 尾语 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 环境使用: python 3.8 解释器 pycharm 编辑器 模块使用: 第三方模块 需要安装 requests —> 发送 HTTP请求 内置模块 不需…

第一阶段-第十二章 Python基础的综合案例(数据可视化-动态柱状图)

目录 引、案例效果一、基础柱状图的构建  1.学习目标  2.通过Bar构建基础柱状图  3.反转x和y轴  4.数值标签在右侧  5.本节的演示  6.本小节的总结 二、基础时间线柱状图  1.学习目标  2.时间线  3. 自动播放  4.时间线的主题  5.本节的代码演示  6.本…

Java经典面试解析:服务器卡顿、CPU飙升、接口负载剧增

01 线上服务器CPU飙升&#xff0c;如何定位到Java代码 解决这个问题的关键是要找到Java代码的位置。下面分享一下排查思路&#xff0c;以CentOS为例&#xff0c;总结为4步。 第1步&#xff0c;使用top命令找到占用CPU高的进程。 第2步&#xff0c;使用ps –mp命令找到进程下…

React中使用Redux

1.为什么要使用redux redux是一个专门用于状态管理的一个库&#xff0c;和vue中的vuex功能类似。其中核心点就是状态的管理。虽然我们无论在vue还是在react中我们组件间的通行都可以使用消息总线或者父子组件间的消息传递来进行操作。但是如果我们需要A组件的状态在其他十个或者…