Java的学习记录:charpter7.集合(ArrayList和LinkedList的区别)

1.集合

1.1集合的概述

1.java集合框架
List , Set, Map都是接口,前两个继承至Collection接口,Map为独立接口。

Set接口的实现类:HashSetLinkedHashSetTreeSet

List接口的实现类:ArrayListVectorLinkedList

Map接口的实现类:HashtableLinkedHashMapHashMapTreeMap

Collection接口下还有个Queue接口,有PriorityQueue
(来自于网络图片)
这里写图片描述
2.集合和数组的区别
(1)长度:
数组:长度固定
集合:长度可变
(2)内容:
数组:可以是基本类型,也可以是引用类型
集合:只能是引用类型
(3)元素内容
数组:只能存储同一类型的元素
集合:可以储存不同类型的元素

3.collection集合的通用方法:

1.在集合末尾添加元素
boolean add(E e)

2.若本类集合中有与o的值相等的元素,则删除该元素,并返回true
boolean remove(Object o)

3.删除本类集合中的所有元素
void clear()

4.判断集合中是否包含某元素
boolean contains(Object o)

5.判断集合是否为空
boolean isEmpty()

6.返回集合中的元素个数
int size()

7.将一个类集合中的所有元素添加到另一个集合中
boolean addAll(Collection <?extends E> c)

8.返回一个包含本类集合中所有元素的数组,数组类型为Obejct[]
Object[] toArray()

9.迭代器,集合的专用遍历方式
Iterator iterator()

1.2Collection集合的分类

Colletion集合接口下分为List接口和Set接口,两者继承于Collection
接口。

1.2.1List接口

List接口的特点是:元素按照进入的先后顺序保存,是有序的,并且元素可以重复。
List的特有功能:

1.在制定位置添加元素
void add(int index, E element)

2.根据指定索引删除元素,并返回该元素
E remove(int index)

3.把指定索引位置的元素替换为指定的值,返回替换前的值
E set(int index, E element)

4.返回指定元素在集合中第一次出现的索引
int indexOf(Obejct o)

5.获取指定位置的元素
E get(int index)

6.列表迭代器
ListIteraror listIterator()

7.截取集合
List subList(int fromIndex, int toIndex)

1.ArrayList:
ArrayList是List接口的一种实现类,相当于是一种动态数组,ArrayList在内存中分配连续的内存空间,它的底层数据结构是数组,数组的特点是每个元素都有自己对应的下标,因而,使用ArrayList访问元素的时候是非常方便的,但是如果进行插入或删除操作时,会存在大量挪位置和分配多余空间的操作,对计算机的性能消耗较大,因而,插入或删除元素较慢
代码演示:

/**
 * @Description  ArrayList 顺序表(动态数组)
 * @date 2020/5/27
 */
public class ArrayList<T> implements List<T>{
    /**
     * 默认初始容量
     */
    private static final int DEFAULT_CAPACITY = 10;
    /**
     * 默认源数据扩容率
     */
    private static final float DEFAULT_EXPAND_RATE = 1.5F;
    /**
     * 核心源数据
     */
    private Object[] elementData;
    /**
     * 常量空数组
     */
    private final Object[] EMPTY_DATA = {};
    /**
     * 数组拷贝的临时记录点
     */
    private Object[] copy = EMPTY_DATA;
    /**
     * 新元素起始位置,当前数组中元素的数量
     */
    private int size;

    public ArrayList(){
        this(DEFAULT_CAPACITY);
    }

    public ArrayList(int initCapacity){
        if(initCapacity==0){
            elementData = EMPTY_DATA;
        }else if(initCapacity>0){
            elementData = new Object[initCapacity];
        }else{
            System.err.println("初始化容量错误:initCapacity "+initCapacity);
        }
    }

    private void ensureCapacity(int needCapacity){
        int expandCapacity = needExpand(needCapacity);
        if(expandCapacity<=0){
            return;
        }
        final int newCapacity = (int)Math.ceil((elementData.length+expandCapacity)*DEFAULT_EXPAND_RATE);
        copy = elementData;
        elementData = new Object[newCapacity];
        System.arraycopy(copy,0,elementData,0,size);
        copy = EMPTY_DATA;
    }

    private int needExpand(int needCapacity){
        return needCapacity - (elementData.length-size);
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public Object[] toArray() {
        return Arrays.copyOf(elementData,size);
    }

    @Override
    public int indexOf(T t) {
        for (int i = 0; i < size; i++) {
            if(elementData[i].equals(t)){
                return i;
            }
        }
        return -1;
    }

    @Override
    public int lastIndexOf(T t) {
        for (int i = size-1; i >= 0; i--) {
            if(elementData[i].equals(t)){
                return i;
            }
        }
        return -1;
    }

    @Override
    public boolean contains(T t) {
        return -1 != indexOf(t);
    }

    @Override
    public void add(T t) {
        ensureCapacity(1);
        elementData[size++] = t;
    }

    @Override
    public void add(T[] arr) {
        ensureCapacity(arr.length);
        System.arraycopy(arr,0,elementData,size,arr.length);
        size += arr.length;
    }

    @Override
    public void add(List<T> list) {
        add((T[])list.toArray());
    }

    @Override
    public T remove(int index) {
        if(index<0 || index>=size){
            throw new ArrayIndexOutOfBoundsException("index out of bounds : "+index);
        }
        T t = (T)elementData[index];
        for (int i = index; i <size-1 ; i++) {
            elementData[i] = elementData[i+1];
        }
        elementData[--size] = null;
        return t;
    }

    @Override
    public boolean remove(T t) {
        int index = indexOf(t);
        if(-1==index){
            return false;
        }
        remove(index);
        return true;
    }

    @Override
    public T get(int index) {
        if(index<0 || index>=size){
            throw new ArrayIndexOutOfBoundsException("index out of bounds : "+index);
        }
        return (T)elementData[index];
    }

    @Override
    public void sort(boolean ascend, Comparator<T> comparator) {
        if(null==elementData || elementData.length<=1) return;
        if(null==comparator) throw new NullPointerException("comparator null pointer exception");
       Arrays.sort((T[])elementData,0,size-1,comparator,ascend);
    }

    //匿名内部类 :接口和抽象类不能直接实例化,但是可以通过匿名内部类实例化
    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            private int index = -1;

            @Override
            public boolean hasNext() {
                return ++index<size;
            }

            @Override
            public T next() {
                return (T)elementData[index];
            }

            @Override
            public T remove() {
                T t = next();
                ArrayList.this.remove(index);
                index--;
                return t;
            }
        };
    }
}

2.LinkedList:
LinkedList:是List接口的一种实现类,本质上是一种链表的形式,根据链表的形式不同又分为单链表双链表,LinkedList分配的空间是不连续的,不具备数组有下标的特征,因而,在访问元素的时候性能较慢,但是因为链表中的每个节点都是独立的关系,因而在执行插入或删除操作的时候较快,无序分配多余的空间,需要多少节点就分配多少空间,性能较高。
LinkedList的特有功能:

添加:
 addFirst()
 addLast()
删除:
 removeFirst()
 removeLast()
获取:
 getFirst()
 getLast()

代码演示:(双向链表

/**
 * @Description  //双向链表
 * @date 2020/6/2
 */
public class LinkedList<T> implements List<T> {


    /**
     * 隐藏在内部的节点:内部类
     * @param <T>
     */
    //匿名内部类,节点类
    private class Node<T> {  //节点类型的类
        Node<T> prev; //节点的上一个引用
        T t;  //节点值的引用
        Node<T> next;//节点的下一个引用


        //既没有前节点,又没有后节点
        public Node(T t) {
            this(null,t,null);
        }

        //有前节点,没有后节点
        public Node(Node<T> prev, T t) {
            this(prev, t, null);
        }

        //有后节点,但是没有前节点
        public Node(T t, Node<T> next) {
           this(null,t,next);
        }

        //既有前节点,又有后节点
        public Node(Node<T> prev, T t, Node<T> next) {
            this.prev = prev;
            this.t = t;
            this.next = next;
        }
    }

    /**
     * 根节点
     */
    private Node<T> root;
    /**
     * 当前节点
     */
    private Node<T> curr;

    /**
     * 当前集合中元素的数量
     */
    private int size;

    public LinkedList() {
    }

    public LinkedList(T t) {
        add(t);
    }


    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public Object[] toArray() {
        Object[] objs = new Object[size];
        Iterator<T> it = iterator();
        int count = 0;
        while(it.hasNext()){
            objs[count++] = it.next();
        }
        return objs;
    }

    @Override
    public int indexOf(T t) {
        Iterator<T> it = _iterator(true);
        int count = -1;
        while(it.hasNext()){
          count++;
          if(it.next().equals(t)){
              return  count;
          }
        }
        return -1;
    }

    @Override
    public int lastIndexOf(T t) {
        Iterator<T> it = _iterator(false);
        int count = size;
        while(it.hasNext()){
            count--;
            if(it.next().equals(t)){
                return count;
            }
        }
        return -1;
    }

    @Override
    public boolean contains(T t) {
        return -1 != indexOf(t);
    }

    @Override
    //向链表中添加元素
    public void add(T t) {
        if (size == 0) { //判空,链表中没有添加元素
            root = new Node<>(t);
            curr = root;  //链表中没有添加元素,后一个即当前添加的元素curr就是根节点root本身
        } else {
            //双向链表
            Node<T> temp = new Node<>(curr, t); //将新增节点temp的前置引用指向curr的内容t
            curr.next = temp;    //将curr的后置引用指向新添加的节点temp
            curr = temp;  //现在temp就是原来的curr
        }
        size++;
    }

    @Override
    //向链表中添加数组(即逐个添加元素)
    public void add(T[] arr) {
        if (null == arr) return; //判空
        for (T t : arr) {
            add(t);  //调用添加元素的方法
        }
    }

    @Override
    //向链表中添加集合(即逐个添加数组)
    public void add(List<T> list) {
        if (null == list) return;
        add((T[]) list.toArray());  //强转,调用添加数组的方法
    }

    private Iterator<T> getByIndex(int index){
        if(index<0 || index>=size){
            throw new ArrayIndexOutOfBoundsException("index out of bounds:"+index);
        }
        Iterator<T> it = _iterator(true);
        while(it.hasNext()){
            if (index-- == 0){
                return it;
            }
        }
        return null;
    }

    @Override
    public T remove(int index) {
       return getByIndex(index).remove();
    }

    @Override
    public boolean remove(T t) {
        boolean removed = false;
        Iterator<T> it = _iterator(true);
        while(it.hasNext()){
            if (it.next().equals(t)){
                it.remove();
                if(!removed){
                    removed = true;
                }
            }
        }
        return removed;
    }

    @Override
    public T get(int index) {
       return getByIndex(index).next();
    }

    @Override
    public void sort(boolean ascend, Comparator<T> comparator) {

    }

    private Iterator<T> _iterator(boolean forward){
        return new Iterator<T>() {
            private Node<T> temp;
            private boolean first = true;


            @Override
            public boolean hasNext() {
                temp = first ? (forward ? root : curr):(forward ? temp.next : temp.prev);
                if (first){
                    first = false;
                }
                return null != temp;
            }

            @Override
            public T next() {
                return temp.t;
            }

            @Override
            public T remove(){
                T t = temp.t;
                Node<T> prev = temp.prev;
                Node<T> next = temp.next;

                if(null !=prev){
                    prev.next = next;
                    temp.prev = null;
                }else{ //如果删除的是第一个
                    root = next;
                    if(forward) {
                        first = true;
                    }
                }
                if (null != next){
                    next.prev = prev;
                    temp.next = null;
                }else { //如果删除的是最后一个
                    curr = prev;
                    if (!forward) {
                        first = true;
                    }
                }
                    if(!first){
                        temp = forward ? prev : next;
                    }
                size--;
                return t;
            }
        };
    }

    @Override
    public Iterator iterator() {
        return _iterator(true);

    }
}

3.Vector
Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素

总结:
1.ArrayList底层数据结构是数组,查询快,增删慢;LinkedList底层结构是链表,查询慢,增删快
2.ArrayList最常用,线程不安全,在查询时效率高;LinkedList线程不安全,但是在增删时,效率高
3.综上所述,在不考虑线程安全的前提下,需要随机快速访问元素时使用ArrayList插入、删除操作较多时使用LinkedList。

1.2.1Set接口

Set接口的特点是:元素是无序的,仅接受一次该元素,元素不可重复,是唯一的,并做内部排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值