• List的使用


    作者~小明学编程 

    文章专栏Java数据结构

    格言目之所及皆为回忆,心之所想皆为过往
    在这里插入图片描述

    目录

    常见方法

    难点分析

    ArrayList(顺序表)

    构造方法

    ArrayList的大小以及增容问题

    打印顺序表

    参考源码实现顺序表(2.0版本)

    List实战练习(扑克牌发牌器)


    常见方法

    方法解释
    boolean add(E e)尾插 e
    void add(int index, E element)将 e 插入到 index 位置
    boolean addAll(Collection 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
    1. public static void main(String[] args) {
    2. ArrayList lis = new ArrayList<>();
    3. lis.add("hello");
    4. lis.add("world");
    5. lis.add("!");
    6. lis.add("hello");
    7. System.out.println(lis);//[hello, world, !, hello]
    8. lis.add(2,"q");
    9. System.out.println(lis);//[hello, world, q, !, hello]
    10. lis.remove(1);
    11. System.out.println(lis);//[hello, q, !, hello]
    12. lis.remove("hello");
    13. System.out.println(lis);//[q, !, hello]
    14. }

    难点分析

    ArrayList(顺序表)

    构造方法

    方法解释
    ArrayList()无参构造
    ArrayList(Collection c)利用其他 Collection 构建 ArrayList
    ArrayList(int initialCapacity)指定顺序表初始容量

    如上表所示我们ArrayList()的构造方法一共有三种,第一种就是我们的无参构造,这种构造方法不用传参数直接new一个顺序表出来。

            ArrayList lis = new ArrayList<>();

    第二种就是有参数的构造方法我们传一个已有的顺序表。

    1. public static void main(String[] args) {
    2. ArrayList lis = new ArrayList<>();
    3. lis.add("q");
    4. lis.add("w");
    5. ArrayList lis1 = new ArrayList<>(lis);
    6. System.out.println(lis1);//[q, w]
    7. }

    第三种则是传参传一个initialCapacity也就是给我们的顺序表一个初始容量。

            ArrayList lis = new ArrayList<>(10);
    

    ArrayList的大小以及增容问题

    1. ArrayList lis = new ArrayList<>();
    2. System.out.println(lis.size());//0

    我们可以看到当我们无参构造的时候我们顺序表的大小居然是0,那么顺表的大小是0的话就肯定不能去放元素进去,所以这中间肯定会进行一个扩容的。我们通过查看源码并分析得出了这样的一个结论。

    如果ArrayList调用不带参数的构造方法,那么顺序表的大小初始为0,当第一次add的时候,整个顺序表的大小将会变成10,之后每次放满在不超过最大增容限制的时候就会进行1.5倍的扩容,如果给定容量的大小了,那么初始值就是给定的大小(不超过最大限制),之后每次满了之后还是进行1.5倍的扩容。

    打印顺序表

    1.直接打印

    System.out.println(lis);//toString方法打印

    2.fori遍历

    1. for (int i=0;i < lis.size();i++) {
    2. System.out.println(lis.get(i));
    3. }

    通过我们的get()方法依次获取指定下标的元素进行打印。

    3.forreach遍历

    1. for (String ret: lis) {
    2. System.out.println(ret);
    3. }

    4.迭代器打印

    1. //迭代器打印
    2. Iterator it = lis.iterator();
    3. while(it.hasNext()) {
    4. System.out.println(it.next());
    5. }
    6. //迭代器list相关打印
    7. ListIterator it2 = lis.listIterator();
    8. while(it.hasNext()) {
    9. System.out.println(it2.next());
    10. }
    public interface ListIterator extends Iterator

    这是我们点开的源码我们可以看到 ListIterator 继承了 Iterator,所以ListIterator中将会有一些 Iterator中所没有的一些方法。

    注意事项:

    在我们使用Iterator的时候remove()之前必须得有next(),不能让迭代器在同一个位置remove()两次,否则的话将会抛出以下的异常。

    1. Iterator it = lis.iterator();
    2. while(it.hasNext()) {
    3. it.remove();
    4. System.out.println(it.next());
    5. }
    Exception in thread "main" java.lang.IllegalStateException

    所以我们想要删除集合中某一个元素的时候我们需要先next()迭代出当前的元素,然后再对其进行一个remove()。

    正确的写法如下:

    1. Iterator it = lis.iterator();
    2. while(it.hasNext()) {
    3. String ret = it.next();
    4. if (ret.equals("hello")) {
    5. it.remove();
    6. } else {
    7. System.out.println(ret);
    8. }
    9. }

    ———————————————————————————————————————————

    利用迭代器在读取的时候插入数据:

    1. ListIterator it2 = lis.listIterator();
    2. System.out.println("============");
    3. while(it2.hasNext()) {
    4. String ret = it2.next();
    5. if (ret.equals("hello")) {
    6. it2.add("hahaha");
    7. } else {
    8. System.out.println(ret);
    9. }
    10. }
    11. System.out.println("===============^");
    12. System.out.println(lis);//[q, !, hello, hahaha]

    值得注意的是我们的迭代器在读取的时候是可以it2.add,但是不能lis.add(),因为我们的ArrayList是单线程的属于线程不安全的,否则的话将会抛出异常。

    参考源码实现顺序表(2.0版本)

    1. class MyArrayList {
    2. private Object[] elementData;//数组
    3. private int useSize;//有效的数据个数
    4. private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//默认的空数组
    5. //不带参数的构造方法
    6. public MyArrayList () {
    7. this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    8. }
    9. //带参数的构造方法
    10. public MyArrayList (int capacity) {
    11. if (capacity>0) {
    12. this.elementData = new Object[capacity];
    13. } else if (capacity==0) {
    14. this.elementData = new Object[0];
    15. } else {
    16. throw new IllegalArgumentException("初始容量小于0了");
    17. }
    18. }
    19. public boolean add (E e) {
    20. //确定一个真正的容量,判断一波是否需要扩容
    21. ensureCapacityInternal(useSize + 1);
    22. //现在可以放心的向里面放元素了
    23. elementData[useSize++] = e;
    24. return true;
    25. }
    26. public void add(int index,E e) {
    27. rangeCheckForAdd(index);
    28. ensureCapacityInternal(useSize+1);
    29. copy(index,e);//拷贝数组
    30. useSize++;
    31. }
    32. public int size() {
    33. return useSize;
    34. }
    35. private void copy(int index,E e) {
    36. for(int i=useSize-1;i>=index;i--) {
    37. elementData[i+1] = elementData[i];
    38. }
    39. elementData[index] = e;
    40. }
    41. private void rangeCheckForAdd(int index) {
    42. if (index > size() || index < 0)
    43. throw new IndexOutOfBoundsException("index的位置不合法!");
    44. }
    45. private void ensureCapacityInternal(int minCapacity) {
    46. //计算得出分析之后的容量
    47. int capacity = calculateCapacity(elementData,minCapacity);
    48. ensureExplicitCapacity(capacity);
    49. }
    50. private void ensureExplicitCapacity(int minCapacity) {
    51. // 若分析之后的容量大于当前的容量则开始扩容
    52. if (minCapacity - elementData.length > 0)
    53. grow(minCapacity);
    54. }
    55. private static int MAX_ARRAY_SIZE = Integer.MAX_VALUE-8;
    56. private void grow(int minCapacity) {
    57. // overflow-conscious code
    58. int oldCapacity = elementData.length;
    59. //确定新的容量的大小
    60. int newCapacity = oldCapacity + (oldCapacity >> 1);//扩大1.5倍
    61. if (newCapacity - minCapacity < 0)
    62. newCapacity = minCapacity;
    63. if (newCapacity - MAX_ARRAY_SIZE > 0)
    64. newCapacity = hugeCapacity(minCapacity);
    65. // minCapacity is usually close to size, so this is a win:
    66. elementData = Arrays.copyOf(elementData, newCapacity);
    67. }
    68. private static int hugeCapacity(int minCapacity) {
    69. if (minCapacity < 0) // overflow
    70. throw new OutOfMemoryError();
    71. return (minCapacity > MAX_ARRAY_SIZE) ?
    72. Integer.MAX_VALUE :
    73. MAX_ARRAY_SIZE;
    74. }
    75. private static int calculateCapacity(Object[] elementData, int minCapacity) {
    76. if (elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//如果没有分配过大小
    77. return Math.max(10,minCapacity);//返回一个10
    78. }
    79. return minCapacity;
    80. }
    81. }

    List实战练习(扑克牌发牌器)

    1. import java.util.ArrayList;
    2. import java.util.List;
    3. import java.util.Random;
    4. //扑克牌类
    5. class Card {
    6. private int rank;//数字
    7. private String suit;//花色
    8. public Card(int rank, String suit) {
    9. this.rank = rank;
    10. this.suit = suit;
    11. }
    12. @Override
    13. public String toString() {
    14. return "[ "+this.suit+" "+this.rank+" ]";
    15. }
    16. }
    17. public class Test {
    18. private static final String[] suits = {"♥","♠","♣","♦"};//花色数组
    19. //买牌
    20. public static List buyCard() {
    21. //new一个顺序表用于存放我们的Card,这边给一个初始值因为我们已只牌的数量
    22. List lis = new ArrayList<>(52);
    23. for (int i = 0; i < 4; i++) {
    24. for (int j = 1; j <= 13; j++) {
    25. String suit = suits[i];
    26. int rank = j;
    27. Card card = new Card(rank,suit);
    28. lis.add(card);
    29. }
    30. }
    31. return lis;
    32. }
    33. //交换两个位置的牌
    34. private static void swap(List cards,int i,int j) {
    35. Card card = cards.get(i);
    36. cards.set(i,cards.get(j));
    37. cards.set(j,card);
    38. }
    39. //定义一个洗牌的方法
    40. public static void shuffle(List cards) {
    41. int size = cards.size();
    42. for (int i = size-1;i>0;i--) {
    43. Random random = new Random();
    44. int rand = random.nextInt(i);
    45. swap(cards,i,rand);
    46. }
    47. }
    48. public static void main(String[] args) {
    49. System.out.println("买牌中");
    50. List cards = buyCard();
    51. System.out.println("洗牌中");
    52. shuffle(cards);
    53. System.out.println("开始发牌");
    54. ArrayList> hand = new ArrayList<>();
    55. List hand1 = new ArrayList<>();
    56. List hand2 = new ArrayList<>();
    57. List hand3 = new ArrayList<>();
    58. hand.add(hand1);
    59. hand.add(hand2);;
    60. hand.add(hand3);
    61. for (int i = 0; i < 5; i++) {
    62. for (int j = 0; j < 3; j++) {
    63. hand.get(j).add(cards.remove(0));
    64. }
    65. }
    66. System.out.println("第1个人的牌"+hand1);
    67. System.out.println("第2个人的牌"+hand2);
    68. System.out.println("第3个人的牌"+hand3);
    69. System.out.println("剩余的牌"+cards);
    70. }
    71. public static void main1(String[] args) {
    72. Card card = new Card(7,"♥");
    73. System.out.println(card.toString());
    74. }
    75. }
  • 相关阅读:
    前端录入音频并上传
    #力扣:26. 删除有序数组中的重复项@FDDLC
    ollama + autogen排雷
    CSS文本样式详解
    计算机网络 --- 网络编程
    【opencv-python】 视频转图片代码
    第三章【ADFS集成Exchang实现OWA\ECP单点登录SSO】配置AD证书服务(配置ADCS)
    C++ 类和对象(7) 对象数组
    java 通过 冰蓝 word 转pdf ,最大程度包装pdf 样式和word接近
    数字电路基础02(用2选1MUX实现与、或、非、与非、或非、异或、同或)
  • 原文地址:https://blog.csdn.net/m0_56911284/article/details/127347132