【Java数据结构 -- List和ArrayList与顺序表】

List和ArrayList与顺序表

  • 一. List
    • 1.1 List介绍
    • 2.1 常见接口介绍
    • 3.1 List的使用
  • 二. ArrayList与顺序表
    • 1.线性表
    • 2.顺序表
      • 2.1 接口的实现
    • 3.ArrayList简介
    • 4. ArrayList使用
      • 4.1 ArrayList的构造
    • 4.2 ArrayList常见操作
    • 4.3 ArrayList的遍历
    • 4.4 ArrayList的扩容机制
    • 5. ArrayList的具体使用
      • 5.1 简单的洗牌算法
      • 5.2 杨辉三角的实现
    • 6 面试题

一. List

1.1 List介绍

在集合框架中,List是一个接口,继承Collection
Iterable <-- Collection <-- List

Collection也是一个接口,该接口中规范了后序容器中常用的一些方法,具体如下所示:
在这里插入图片描述
Iterable也是一个接口,表示实现该接口的类是可以逐个元素进行遍历的,具体如下:
在这里插入图片描述
站在数据结构的角度来看,List就是一个线性表,即n个具有相同类型元素的有限序列,在该序列上可以执行增删改查以及变量等操作

2.1 常见接口介绍

List中提供了很多方法,具体的常用方法如下:
方法 ---- 解释
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

3.1 List的使用

List是一个接口,并不是直接用来实例化
如果要使用的话必须先去实例化List的实现类,ArrayLsit和LinkedList都实现了List接口。

二. ArrayList与顺序表

1.线性表

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

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储
在这里插入图片描述

2.顺序表

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

2.1 接口的实现

IList接口:

public interface IList {// 新增元素,默认在数组最后新增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();// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的public void display();Boolean isFull();Boolean isEmpty();
}

实现ArrayList方法:

public class MyArrayList implements IList{public int[] elem;public int usedSize;public static final int DEFAULT_CAPACITY = 5;public MyArrayList() {elem = new int[DEFAULT_CAPACITY];}@Overridepublic void display() {for (int i = 0; i < this.usedSize; i++) {System.out.println(elem[i]+" ");}System.out.println();}@Overridepublic void add(int data) {// 判断是否满了 满了就要扩容if (isFull()) {elem = Arrays.copyOf(elem,elem.length*2);}this.elem[usedSize] = data;this.usedSize++;}@Overridepublic Boolean isFull() {return this.usedSize == DEFAULT_CAPACITY;}@Overridepublic void add(int pos, int data) {// pos位置的判断checkPosOfAdd(pos);if (isFull()) {elem = Arrays.copyOf(elem,elem.length*2);}for (int i = this.usedSize-1; i >= pos; i--) {this.elem[i+1] = elem[i];}this.elem[pos] = data;this.usedSize++;System.out.println();}private void checkPosOfAdd(int pos) {if (pos<0 || pos >this.usedSize) {throw new PosException("Pos位置为:"+ pos);}}@Overridepublic boolean contains(int toFind) {for (int i = 0; i < this.usedSize; i++) {if (elem[i] == toFind){return true;}}return false;}@Overridepublic int indexOf(int toFind) {for (int i = 0; i < this.usedSize; i++) {if (elem[i] == toFind) {return i;}}return -1;}// 获取pos位置的值@Overridepublic int get(int pos) {// 判断pos位置checkPosOfGet(pos);// 为空if (isEmpty()) {throw new EmptyException("顺序表为空");//return -1;}return this.elem[pos];}public Boolean isEmpty() {return usedSize ==0;}private void checkPosOfGet(int pos){if (pos < 0 || pos >= this.usedSize) {throw new PosException("Pos位置不合法:"+pos);}}// 更新pos位置的值为value@Overridepublic void set(int pos, int value) {checkPosOfGet(pos);if (isEmpty()) {System.out.println("顺序表为空");}this.elem[pos] = value;}// 删除toRemove这个值@Overridepublic void remove(int toRemove) {if (isEmpty()) {throw new EmptyException("顺序表为空");}int index=indexOf(toRemove);for (int i = index; i < this.usedSize-1; i++) {this.elem[i] = this.elem[i+1];}this.usedSize--;}@Overridepublic int size() {return this.usedSize;}//清空顺序表  防止数据泄露@Overridepublic void clear() {this.usedSize = 0;}
}

注意

  • 在定义了一个空顺序表的时候第一次add分配了默认的内存大小
  • 在扩容的时候是以1.5倍扩容
    Main测试:
public static void main2(String[] args) {
/*        ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(10);arrayList.add(20);arrayList.add(30);arrayList.add(0,99);*///第一次add的时候  分配了内存大小为10//扩容的时候 是1.5倍扩容ArrayList<Integer> arrayList1 = new ArrayList<>();arrayList1.add(10);arrayList1.add(20);arrayList1.add(30);// 传入的参数是E类型或者是E类型的子类ArrayList<Number> arrayList2 = new ArrayList<>(arrayList1);arrayList2.add(9999);System.out.println(arrayList2);//[10, 20, 30, 9999]//list 通过sublist截取后 指向的还是arrayList2所指向的内容 即list和arrayList2指向的内容一致// 所以修改list指向的内容就是 arrayList2的值也会变List<Number> list = arrayList2.subList(0,2);System.out.println(list);//[10, 20]System.out.println("=====");list.set(0,199);System.out.println(arrayList2);  //[199, 20, 30, 9999]System.out.println(list);       //[199, 20]}public static void main1(String[] args) {MyArrayList myArrayList = new MyArrayList();myArrayList.add(1);myArrayList.add(2);myArrayList.add(3);myArrayList.add(4);myArrayList.add(5);myArrayList.add(6);System.out.println(myArrayList.contains(3));System.out.println(myArrayList.indexOf(5));myArrayList.remove(3);myArrayList.display();}

3.ArrayList简介

在集合框架中,ArrayList是一个普通的类,实现了List接口,具体框架图如下:
在这里插入图片描述注意:

  1. ArrayList是以泛型方式实现的,使用时必须要先实例化
  2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
  3. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
  4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
  5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
  6. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

4. ArrayList使用

4.1 ArrayList的构造

在这里插入图片描述
注意在这里的extends E 传入的是E类型或者是E的子类型

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

4.2 ArrayList常见操作

方法 ------ 解释
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

    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,否则返回falseif(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 可以使用三方方式遍历:for循环+下标、foreach、使用迭代器

    public static void main(String[] args) {ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(10);arrayList.add(20);arrayList.add(30);//ArrayList的遍历//第一种遍历方式   重写了toString方法System.out.println(arrayList);//第二种遍历方式for (int i = 0; i < arrayList.size(); i++) {System.out.print(arrayList.get(i)+" ");}System.out.println();//3.for-eachfor (int x:arrayList) {System.out.print(x+" ");}System.out.println();// 4. 迭代器Iterator<Integer> it = arrayList.iterator();while (it.hasNext()) {System.out.print(it.next()+" ");}System.out.println();//5. ListIterator  是 Iterator的子类ListIterator<Integer> it2 = arrayList.listIterator();while (it2.hasNext()) {System.out.print(it2.next()+" ");}System.out.println();//6. 从后往前打印ListIterator<Integer> it3 = arrayList.listIterator();while (it2.hasPrevious()) {System.out.print(it2.previous()+" ");}System.out.println();}

4.4 ArrayList的扩容机制

ArrayList是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容。
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);}return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (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进行扩容

5. ArrayList的具体使用

5.1 简单的洗牌算法

Card:

public class Card {public String suit;public int num;public Card(String suit, int num) {this.suit = suit;this.num = num;}@Overridepublic String toString() {/*return "Card{" +"suit='" + suit + '\'' +", num=" + num +'}';*/return suit +""+num;}
}

Cardgame:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class Cardgame {public static final String[] suits = {"♥","♣","♦","♠"};// 买牌 (创建牌)public List<Card> buyCard() {List<Card> cardList = new ArrayList<>();for (int i = 0; i < 4; i++) {for (int j = 0; j < 13; j++) {cardList.add(new Card(suits[i],j));//相当于下面代码/*String suit = suits[i];Card card = new Card(suit,j)cardList.add(card);*/}}return cardList;}// 洗牌public void shuffle(List<Card> cardList) {Random random = new Random();for (int i = cardList.size()-1; i > 0; i--) {int index = random.nextInt(i);swap(cardList,i,index);}}private static void swap(List<Card> cardList,int i,int j) {Card tmp = cardList.get(i);cardList.set(i,cardList.get(j));cardList.set(j,tmp);}// 发牌 3个人每个人轮流抓5张牌// 思路:1.每个人拿到牌 放到哪//      2. l轮流怎么抓5张牌public List<List<Card>> getCard(List<Card> cardList) {List<Card> hand1 = new ArrayList<>();List<Card> hand2 = new ArrayList<>();List<Card> hand3 = new ArrayList<>();List<List<Card>> hand = new ArrayList<>();hand.add(hand1);hand.add(hand2);hand.add(hand3);for (int i = 0; i < 5; i++) {  // 拿五次牌for (int j = 0; j < 3; j++) {  // 3个人//怎么揭牌?  每次相当于 删除下0标这个牌Card card = cardList.remove(0);// 怎么放到对应人的手里面?hand.get(j).add(card);}}return hand;}
}

Main测试:

import java.util.List;public class Main {public static void main(String[] args) {Cardgame cardgame = new Cardgame();List<Card> ret = cardgame.buyCard();System.out.println("买牌:");System.out.println(ret);cardgame.shuffle(ret);System.out.println("洗牌:");System.out.println(ret);System.out.println("揭牌:");List<List<Card>> hand = cardgame.getCard(ret);for (int i = 0; i < hand.size(); i++) {System.out.println("第"+(i+1)+"个人的牌"+hand.get(i));}System.out.println("剩下的牌");System.out.println(ret);}}

在这里插入图片描述

5.2 杨辉三角的实现

具体要求:
在这里插入图片描述

    public List<List<Integer>> generate(int numRows) {// 定义一个二维数组List<List<Integer>> ret = new ArrayList<>();List<Integer> list = new ArrayList<>();list.add(1);ret.add(list);for (int i = 1; i < numRows; i++) {//每循环一次  就是一行List<Integer> curRow = new ArrayList<>();curRow.add(1);  //每行的第一个元素//处理中间的数字List<Integer> preRow = ret.get(i-1);for (int j = 1; j < i; j++) {int x = preRow.get(j)+preRow.get(j-1);curRow.add(x);}//处理最后一个数字curRow.add(1);ret.add(curRow);}return ret;}

6 面试题

CVTE面试题:
str1:“welcome to cvte”
str2: “come”
删除字符串1当中,出现的所有字符串2当中的字符, 即结果为 “wl t vt”

public class Test {public static List<Character> func(String str1,String str2) {List<Character> list = new ArrayList<>();for (int i = 0; i < str1.length(); i++) {char ch = str1.charAt(i);if(!str2.contains(ch+"")) { //contains接收的是字符串  所以字符ch +""list.add(ch);}}return list;}public static void main(String[] args) {List<Character> ret = func("welcome to cvte","come");for (Character ch:ret) {System.out.print(ch);}}
}

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

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

相关文章

Http协议与Tomcat

HTTP协议 HTTP协议&#xff08;HyperText Transfer Protocol&#xff09;即超文本传输协议 &#xff0c;是TCP/IC网络体系结构应用层的一个客户端-服务端协议&#xff0c;是所有客户端&#xff0c;服务端数据传输的基石&#xff08;数据传输规则&#xff09; 特点 ⭐基于TCP协…

验证码的多种生成策略

&#x1f60a; 作者&#xff1a; 瓶盖子io &#x1f496; 主页&#xff1a; 瓶盖子io-CSDN博客 第一种 a.导入依赖 <dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.10</ver…

冷却液泵现场案例:施耐德EOCR-FMZ2在冷却液泵设备上的使用

热水泵和冷却液泵是现代工业及建筑设施中不可或缺的部件。它们分别在热能传递和冷却系统中扮演着重要角色。本文将探讨施耐德EOCR-FMZ2在冷却液泵设备上的应用案例&#xff0c;展示其如何提高系统效率和安全性。 冷却液泵通常用于工业生产中&#xff0c;用来维持机械设备在适宜…

关于最长上升子序列的动态规划问题的优化算法(二分搜索)

最长递增子序列 暴力解法&#xff1a; 思路&#xff1a;使用动态规划的思想&#xff0c;判断当前元素之前的所有元素&#xff0c;如果比当前元素小&#xff0c;则修改当前元素的最长递增子序列&#xff08;需判断是否需要修改&#xff09;。 时间复杂度&#xff1a;O(n^2) im…

“分割“安卓用户,对标iOS,鸿蒙崛起~

近期关于**“华为于明年推出不兼容安卓的鸿蒙版本”**的消息传出&#xff0c;引起了业界的热议关注。自从2019年8月&#xff0c;美国制裁下&#xff0c;华为不再能够获得谷歌安卓操作系统相关付费服务&#xff0c;如此情况下&#xff0c;华为“备胎”鸿蒙操作系统一夜转正。 华…

虚拟化之指令的Trap和仿真

有时,虚拟机监控程序需要在虚拟机(VM)中模拟操作。例如,VM内的软件可能尝试配置与功耗管理或缓存一致性相关的低级处理器控件。通常,您不希望将VM直接访问这些控件,因为它们可能被用于突破隔离,或影响系统中的其他VM。 trap在执行给定操作(例如读取寄存器)时引发异常…

UEC++ 探索虚幻5笔记 day11

虚幻5.2.1探索 项目目录探索 C工程一定不能是中文路径&#xff0c;中文项目名&#xff0c;最好全部不要用中文&#xff0c;蓝图项目可以是中文浅浅创建一个空项目&#xff0c;讲解一下之前UE4没有讲解的项目目录文件的分布组成 .vs&#xff1a;文件夹一般是项目编译缓存文件夹…

探索SpringBoot发展历程

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 循序渐进学SpringBoot ✨特色专栏&…

matplot函数调整子图大小测试

调整subplot()函数的子图间距 import numpy as np import matplotlib.pyplot as plt for i in range(1,7):figsize 10,6plt.subplot(2,3,i)plt.text(0.5,0.5,str((2,3,i)),fontsize18,hacenter) **plt.subplots_adjust(hspace3.3, wspace0.3)** plt.show()import numpy as np…

AV1编码技术分享指南 ‍

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

【STM32】TIM定时器输入捕获

1 输入捕获 1.1 输入捕获简介 IC&#xff08;Input Capture&#xff09;输入捕获 输入捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff08;上升沿/下降沿&#xff09;&#xff0c;当前CNT的值将被锁存到CCR中&#xff08;把CNT的值读出来&#xff0c;写入到…

动态设置当前按钮是否可以点击

当审核状态为通过时不可以点击审核按钮 <vxe-columnfixed"right"align"center"width"100"title"操作"><template slot-scope"scope"><el-button v-if"hasPermission(basic:archivalInfo:edit)":di…