zoukankan      html  css  js  c++  java
  • 集合(2)——List集合

    一、概念

    List接口是Collection接口的子接口,是一种有序、可重复的集合

    二、常见方法

     其他详细的部分可以查阅API

    三、常用的实现类

    1)ArrayList

     

     List list1 = new ArrayList();

    底层数据结构是数组,查询快,增删慢;线程不安全,效率高。

    ArrayList和Vector中数组的初始化容量都是10。

    如果要考虑多线程安全问题,建议使用Collections.synchronizedList()方法将ArrayList转成线程安全的集合,而不使用Vector集合。

    注意,ArrayList中的元素:

    1.允许为空

    2.允许重复

    3.有序

    4.线程不安全

    5.遍历时使用for循环速度高于foreach循环

     1 public class ArrayListDemo {
     2     public static void main(String[] args) {
     3         List<Hero> heros = new ArrayList<>();
     4         //集合的添加
     5         heros.add(new Hero("爆破"));
     6         heros.add(new Hero("龙卷"));
     7         heros.add(new Hero("银色獠牙"));
     8         heros.add(new Hero("King"));
     9         //集合的遍历:iterator方式
    10         Iterator<Hero> it = heros.iterator();
    11         while(it.hasNext()) {
    12             Hero hero = it.next();
    13             System.out.println(hero.name);
    14         }
    15         //修改,因为底层封装了一个数组,所以索引从0开始
    16         heros.set(0, new Hero("秃头披风侠"));
    17         //获取
    18         System.out.println(heros.get(0).name);
    19         //批量删除,单个删除用remove
    20         heros.removeAll(heros);
    21         System.out.println(heros.size());
    22     }
    23 }
    24 
    25 class Hero {
    26     String name;
    27 
    28     public Hero(String name) {
    29         this.name = name;
    30     }
    31 }
    View Code

    有一点需要注意的是,在遍历List的过程中不可以使用remove的方式删除元素

     1 public class ArrayListDemo {
     2     public static void main(String[] args) {
     3         List<Hero> heros = new ArrayList<>();
     4         //集合的添加
     5         heros.add(new Hero("爆破"));
     6         heros.add(new Hero("龙卷"));
     7         heros.add(new Hero("银色獠牙"));
     8         heros.add(new Hero("King"));
     9         //在遍历的过程中使用remove删除
    10         for (Hero hero : heros) {
    11             if(hero.name.equals("King"))
    12                 heros.remove(hero);
    13         }
    14    }     
    View Code

    否则就会报这样的异常

     如果要在遍历的过程中删除元素,可以使用迭代器方式:

    2)LinkedList

    LinkedList和ArrayList一样,也实现了List接口。那些常用方法不再赘述,同时还实现了双向链表结构Deque接口,可以很方便的在头尾插入数据。

    它的底层数据结构是链表,查询慢,增删快;线程不安全,效率高。

    什么是链表结构?

    一种线性的存储结构,将要存储的数据存在存储单元中,这个单元除了数据外,还存储了下个存储单元的地址(有些还会存放上个存储单元的地址),每次查找数据的时候,通过这个地址去找到下一个存储单元。

    双向链表的话,不仅每个存储单元有指向上一个和下一个单元的地址,链表的尾结点和头结点也是相连的。

    注意,LinkedList中的元素:

    1.允许为空

    2.允许重复

    3.有序

    4.线程不安全

    5.遍历时使用foreach速度远高于for循环

     1 public class LinkedListDemo {
     2     public static void main(String[] args) {
     3         LinkedList<Hero> heros = new LinkedList<>();
     4         heros.addFirst(new Hero("兔头披风侠"));
     5         heros.addFirst(new Hero("魔鬼改造人"));
     6         heros.addLast(new Hero("King"));
     7         System.out.println(heros);
     8         //查看头元素
     9         System.out.println(heros.getFirst());
    10         //查看尾元素
    11         System.out.println(heros.getLast());
    12     }
    13 }
    View Code

    除了上述两种接口以外,LinkedList还实现了Queue接口,是一种先进先出的数据结构。

    常用方法:

    peek():查看第一个元素

    poll():取出第一个元素,该元素会在队列中被删除

    offer():在队列最后添加元素

     1 Queue<Hero> que = new LinkedList<>();
     2         que.offer(new Hero("秃头披风侠"));
     3         que.offer(new Hero("魔鬼改造人"));
     4         que.offer(new Hero("King"));
     5         System.out.println(que);
     6         System.out.println("查看第一个元素");
     7         System.out.println(que.peek());
     8         System.out.println("取出所有元素");
     9         while(que.size()>0)
    10             System.out.println(que.poll());
    11         System.out.println(que);
    View Code

    使用LinkedList模拟栈

     1 class LinkedStack<E> {
     2     LinkedList<E> list;
     3     public LinkedStack(){
     4         list = new LinkedList<E>();
     5     }
     6 
     7     public void push(E ele) {
     8         list.addFirst(ele);
     9     }
    10 
    11     public E pop(){
    12        return list.removeFirst();
    13     }
    14 
    15     public E peek(){
    16         return list.getFirst();
    17     }
    18 
    19     public int size(){
    20         return list.size();
    21     }
    22 }
    View Code

    3)Vector

    List list2 = new Vector();

    底层数据结构是数组,查询快,增删慢;线程安全,效率低,几乎已经淘汰了这个集合

    四、ArrayList的优缺点

    从上面的几个过程总结一下ArrayList的优缺点。ArrayList的优点如下:

    1、ArrayList底层以数组实现,是一种随机访问模式,再加上它实现了RandomAccess接口,因此查找也就是get的时候非常快

    2、ArrayList在顺序添加一个元素的时候非常方便,只是往数组里面添加了一个元素而已

    不过ArrayList的缺点也十分明显:

    1、删除元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能

    2、插入元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能

    因此,ArrayList比较适合顺序添加、随机访问的场景

     

     

    五、LinkedList和ArrayList的对比

    1、顺序插入速度ArrayList会比较快,因为ArrayList是基于数组实现的,数组是事先new好的,只要往指定位置塞一个数据就好了;LinkedList则不同,每次顺序插入的时候LinkedList将new一个对象出来,如果对象比较大,那么new的时间势必会长一点,再加上一些引用赋值的操作,所以顺序插入LinkedList必然慢于ArrayList

    2、基于上一点,因为LinkedList里面不仅维护了待插入的元素,还维护了Entry的前置Entry和后继Entry,如果一个LinkedList中的Entry非常多,那么LinkedList将比ArrayList更耗费一些内存

    3、数据遍历的速度,看最后一部分,这里就不细讲了,结论是:使用各自遍历效率最高的方式,ArrayList的遍历效率会比LinkedList的遍历效率高一些

    4、有些说法认为LinkedList做插入和删除更快,这种说法其实是不准确的:

    (1)LinkedList做插入、删除的时候,慢在寻址,快在只需要改变前后Entry的引用地址

    (2)ArrayList做插入、删除的时候,慢在数组元素的批量copy,快在寻址

    所以,如果待插入、删除的元素是在数据结构的前半段尤其是非常靠前的位置的时候,LinkedList的效率将大大快过ArrayList,因为ArrayList将批量copy大量的元素;越往后,对于LinkedList来说,因为它是双向链表,所以在第2个元素后面插入一个数据和在倒数第2个元素后面插入一个元素在效率上基本没有差别,但是ArrayList由于要批量copy的元素越来越少,操作速度必然追上乃至超过LinkedList

    从这个分析看出,如果你十分确定你插入、删除的元素是在前半段,那么就使用LinkedList;如果你十分确定你删除、删除的元素在比较靠后的位置,那么可以考虑使用ArrayList。如果你不能确定你要做的插入、删除是在哪儿呢?那还是建议你使用LinkedList吧,因为一来LinkedList整体插入、删除的执行效率比较稳定,没有ArrayList这种越往后越快的情况;二来插入元素的时候,弄得不好ArrayList就要进行一次扩容,记住,ArrayList底层数组扩容是一个既消耗时间又消耗空间的操作

  • 相关阅读:
    beta版本冲刺七
    beta版本冲刺六
    beta版本冲刺五
    beta版本冲刺四
    beta版本冲刺三
    Beta版本冲刺(二)
    项目评测
    beta版本冲刺(一)
    福大软工 · 最终作业
    福大软工 · 第十二次作业
  • 原文地址:https://www.cnblogs.com/blogforvi/p/11624328.html
Copyright © 2011-2022 走看看