ArrayList与顺序表

目录

1.线性表

2.顺序表

2.1 接口的实现

3. ArrayList简介

4. ArrayList使用

4.1 ArrayList的构造

4.2 ArrayList常见操作

4.2.1应用实例

4.3 ArrayList的遍历

4.4 ArrayList的扩容机制

5. ArrayList的具体使用

5.1 简单的洗牌算法

具体实现的含义

选择具体实现的理由


1.线性表

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

2.顺序表

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

2.1 接口的实现

public class SeqList {
private int [] array ;
private int size ;
// 默认构造方法
SeqList (){ }
// 将顺序表的底层容量设置为 initcapacity
SeqList ( int initcapacity ){
}

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的构造

arrayList当前对象的方法
LIst是接口
list:此时通过list访问的是接口中的方法
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 );
}

缺点:
1.对于ArrayList来说 不方便 插入和删除 因为要移动数组元素,最坏情况下,0下标插入,得移动所有元素。删除0下标 也得移动所有元素
2.扩容可能会浪费空间,假设现在100个长度放满了。还一个元素没有放,假设此时扩容,多了50个。但是实际只放了1个元素。

优点:
适合 根据下标进行 查找 和 更新的场景

4.2 ArrayList常见操作

// 新增元素,默认在数组最后新增
public void add(int data) { }
// 在 pos 位置新增元素
public void add(int pos, int data) { }
// 判定是否包含某个元素
public boolean contains(int toFind) { return true; }
// 查找某个元素对应的位置
public int indexOf(int toFind) { return -1; }
// 获取 pos 位置的元素
public int get(int pos) { return -1; }
// 给 pos 位置的元素设为 value
public void set(int pos, int value) { }
//删除第一次出现的关键字key
public void remove(int toRemove) { }
// 获取顺序表长度
public int size() { return 0; }
// 清空顺序表
public void clear() { }
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display() { }
}

4.2.1应用实例

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 可以使用三方方式遍历: 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. 迭代器是设计模式的一种,后序容器接触多了再给大家铺垫

4.4 ArrayList的扩容机制

下面代码有缺陷吗?为什么?
public static void main ( String [] args ) {
List < Integer > list = new ArrayList <> ();
for ( int i = 0 ; i < 100 ; i ++ ) {
list . add ( i );
}
}
ArrayList 是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容。以下是 ArrayList 源码中扩容方式:
 add.扩容机制(1.5倍扩容)

总结

1. 检测是否真正需要扩容,如果是调用 grow 准备扩容
2. 预估需要库容的大小
初步预估按照 1.5 倍大小扩容 ,如果用户所需大小超过预估1.5 倍大小,则按照用户所需大小扩容
真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
3. 使用 copyOf 进行扩容

5. ArrayList的具体使用

5.1 简单的洗牌算法

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 手中的牌:");

运行结果

List<Card> deck = new ArrayList<>(52);能不能改成ArrayList<Card> deck = new ArrayList<>(52)

ArrayList 的具体实现是指它是 List 接口的一种具体实现方式。在 Java 中,List 是一个接口,它定义了一组操作列表的基本方法,如添加、删除、访问元素等。ArrayListList 接口的一个具体实现类,使用动态数组来存储元素。

具体实现的含义

  • 接口 vs 实现:接口(如 List)只定义了方法的签名和行为,而不提供具体的实现细节。具体实现类(如 ArrayList)提供了这些方法的具体行为和内部数据结构的实现。

  • 不同的实现类:Java 提供了多个 List 接口的实现类,比如:

    • ArrayList:基于动态数组实现,支持随机访问,增删操作的性能较好,但在中间插入或删除元素时效率较低。
    • LinkedList:基于链表实现,适合频繁插入和删除操作,但随机访问性能较差。

选择具体实现的理由

  • 性能需求:根据你的应用场景,选择适合的实现可以提高程序的性能。例如,如果你需要频繁插入和删除元素,LinkedList 可能更合适;而如果你需要快速随机访问,ArrayList 更有效。

  • 内存使用:不同的实现类在内存管理上也有所不同。ArrayList 在元素增加时可能需要重新分配内存,而 LinkedList 则在插入时可能会有额外的内存开销。


 到这里,竹竹零就要和大家说再见了🍕🍕🍕

如果您觉得有失偏颇请您在评论区指正,如果您觉得不错的话留个好评再走吧!!

您的鼓励就是对我最大的支持!  ! !

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值