Java容器之List

1、Java集合概览

Java的容器有ListQueueSetMap等。从上图可以看出,除了以Map结尾的类之外,其他类都实现了Collection接口。以Map结尾的类实现了Map接口。

2、说一说这些容器都有什么区别?

  • List:存储的元素是有序的、可重复的。
  • Set:存储的元素是无序的、不可重复的。
  • Queue:FIFO(先进先出)
  • Map:使用键值对(key-value)存储,类似于数学上的函数 y=f(x),“x”代表 key,"y"代表 value,Key 是无序的、不可重复的;value 是无序的、可重复的,每个键最多映射到一个值。

3、List底层的数据结构

  • ArrayList:Object[](数组),是List的主要实现类,线程不安全。
  • Vector:Object[],是List的古老实现类。与ArrayList不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢,一般也不推荐使用。
  • LinkedList:双向链表

4、ArrayList和LinkedList的区别?

5、ArrayList实现代码

package JavaContainer;
/*ArrayList泛型类的实现*/
import java.util.Arrays;
import java.util.Iterator;

public class MyList<AnyType> implements Iterable<AnyType> {
    //list 默认初始容量
    private final static int DEFAULT_CAPACITY = 10;

    //MyList包含元素的个数
    private int theSize;

    //theItems数组
    private AnyType[] theItems;

    //空数组
    private static final Object[] EMPTY_ELEMENTDATA = {};

    //用于默认大小的共享空数组实例,以知道在添加第一个元素时容量需要增加多少。
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //保存ArrayList数据的数组
    transient Object[] elementData;

    //得到最小扩容量
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // 获取“默认的容量”和“传入参数”两者之间的最大值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

    /**判断是否需要扩容**/
    private void ensureExplicitCapacity(int minCapacity) {
        //modCount++; 扩容次数
        if (minCapacity - elementData.length > 0)
            //调用grow方法进行扩容,调用此方法代表已经开始扩容了
            grow(minCapacity);
    }
    /**要分配的最大数组大小**/
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**ArrayList扩容的核心方法**/
    private void grow(int minCapacity) {
        // oldCapacity为旧容量,newCapacity为新容量
        int oldCapacity = elementData.length;

        //将新容量更新为旧容量的1.5倍(位运算速度快)
        int newCapacity = oldCapacity + (oldCapacity >> 1);

        //然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;

        //再检查新容量是否超出了ArrayList所定义的最大容量,若超出了,则调用hugeCapacity()来比较minCapacity和 MAX_ARRAY_SIZE,
        //如果minCapacity大于MAX_ARRAY_SIZE,则新容量则为Interger.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE。
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);

        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    //比较minCapacity和 MAX_ARRAY_SIZE
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0)
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }


    //默认无参构造
    public MyList() {
        doclear();
    }

    //清空MyList
    public void clear(){
        doclear();
    }

    private void doclear() {
        theSize = 0;
        ensureCapcity(DEFAULT_CAPACITY);
    }

    //扩容,将Mylist的最大容量扩充到newCapcity
    public void ensureCapcity(int newCapcity) {
        if (newCapcity < DEFAULT_CAPACITY) return;

        AnyType[] old = theItems;
        theItems = (AnyType[]) new Object[newCapcity];  //直接定义泛型的数组是非法的,只能先用Object定义在转换

        for(int i = 0; i < size(); i++) {
            theItems[i] = old[i];
        }
    }

    //返回此list的大小
    public int size() {
        return theSize;
    }

    //判断list是否为空
    public boolean isEmpty() {
        return size() == 0;
    }

    //修改Mylist的容量为当前列表的大小,节省存储空间
    public void trimToSize() {
        ensureCapcity(size());
    }

    //查询下标为idx的值
    public AnyType get(int idx){
        if(idx < 0 || idx > size())
            throw new ArrayIndexOutOfBoundsException();
        return theItems[idx];
    }

    //将下标为idx的元素设置为newVal,并返回覆盖前的值
    public AnyType set(int idx, AnyType newVal) {
        if(idx < 0 || idx > size())
            throw new ArrayIndexOutOfBoundsException();

        AnyType old = theItems[idx];
        theItems[idx] = newVal;
        return old;
    }

    public boolean add(AnyType x) {
        //一个参数的add默认添加到list最后,size()表示可以被放置的位置
        add(size(), x);
        return true;
    }

    public void add(int idx, AnyType x){
        if (idx < 0 || idx > size())
            throw new ArrayIndexOutOfBoundsException();

        //list的容量满了,进行扩容
        if(theItems.length == size())
            ensureCapcity(size() * 2 + 1);  //扩容

        for(int i = theSize; i > idx; i--)
            theItems[i] = theItems[i-1];

        theItems[idx] = x;
        theSize++;
    }

    //将idex处的元素移除,并返回被移除的元素
    public AnyType remove(int idx) {
        AnyType removeItem = theItems[idx];

        for(int i = idx; i < size(); i++)
            theItems[i] = theItems[i+1];

        theSize--;
        return removeItem;
    }

    //内部类ArrayListIterator实现了针对于MyList类的Iterator<AnyType>接口
    private class ArrayListIterator implements java.util.Iterator<AnyType> {
        private int current = 0;    //跟踪当前元素的索引

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

        @Override
        public AnyType next() {
            if(!hasNext())
                throw new java.util.NoSuchElementException();
            return theItems[current++];
        }

        public void remove() {
            MyList.this.remove(--current);
        }
    }

    @Override
    public Iterator<AnyType> iterator() {
        return new ArrayListIterator();
    }

    public static void main(String[] args) {
        //test()
    }
}

 

6、LinkedList的实现代码

package JavaContainer;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class MyLinkedList<AnyType> implements Iterable<AnyType> {

    private static class Node<AnyType> {
        public AnyType data;
        public Node<AnyType> prev;  //指向前一个节点的指针
        public Node<AnyType> next;  //指向后一个节点的指针

        //构造函数
        public Node(AnyType x, Node<AnyType> p, Node<AnyType> q){
            data = x; prev = p; next = q;
        }
    }

    //MyLinkedList的数据成员
    private int theSize;
    private int modCount = 0;   //add、remove、clear时才修改
    private Node<AnyType> beginMarker;  //头结点,作额外的标记
    private Node<AnyType> endMarker;    //尾节点,作额外的标记

    //无参构造
    public MyLinkedList() {
        doclear();
    }

    //清理
    public void clear() {
        doclear();
    }

    private void doclear() {    //只有两个标记节点
        beginMarker = new Node<AnyType>(null, null,null);
        endMarker = new Node<AnyType>(null, beginMarker,null);

        beginMarker.next = endMarker;
        modCount ++;
        theSize = 0;    //这个theSize指的是有效地theSize,标记节点不算
    }

    //获取当前MyLinkedList的大小
    public int size() {
        return theSize;
    }
    //判断当前MyLinkedList是否为空
    public boolean isEmpty() {
        return size() == 0;
    }

    //在尾部添加新元素x
    public boolean add(AnyType x) {
        add(size(), x);
        return true;
    }

    public void add(int idx, AnyType x) {
        Node<AnyType> p = getNode(idx, 0, size()-1);
        addBefore(p ,x);  //先找到这个节点,然后再插入
    }

    //已经确定插入节点的位置,插入节点
    private void addBefore(Node<AnyType> p, AnyType x) {
        Node<AnyType> newNode = new Node<AnyType>(x, p.prev, p);
        newNode.prev.next = newNode;
        p.prev = newNode;

        theSize++;
        modCount++;
    }

    //得到idx节点处的值(而不是引用)
    public AnyType get(int idx) {
        return getNode(idx).data;
    }

    //查找(在默认范围内)
    private Node<AnyType> getNode(int idx) {
        return getNode(idx, 0 , size() - 1);
    }

    //查找(在指定范围内)
    private Node<AnyType> getNode(int idx, int lower, int upper) {
        Node<AnyType> p;

        if(idx < lower || idx > upper)
            throw new IndexOutOfBoundsException();

        //分成两部分能提高查找的效率
        if(idx < size() / 2) {  //前半部分
            p = beginMarker.next;
            for(int i = 0; i < idx; i++) {
                p = p.next;
            }
        }

        else {  //后半部分
            p = endMarker;
            for(int i = size(); i > idx; i--) {
                p = p.prev;
            }
        }
        return p;
    }

    public AnyType set(int idx, AnyType newVal) {
        Node<AnyType> p = getNode(idx);
        AnyType oldVal = p.data;
        p.data = newVal;
        return  oldVal;
    }

    public AnyType remove(int idx) {
        return remove(getNode(idx));
    }
    //remove idx处的节点,并返回删除的值
    private AnyType remove(Node<AnyType> p) {
        p.prev.next = p.next;
        p.next.prev = p.prev;

        theSize--;
        modCount++;
        //有人可能会有疑问,没用的节点p占据的空间没有释放,注意因为JVM中有垃圾回收机制,不需要程序员手动释放
        return p.data;
    }

    //MyLinkedList继承Iterable接口,重写Iterator方法
    @Override
    public Iterator<AnyType> iterator() {
        return new LinkedListIterator();
    }

    //内部类(迭代器中主要实现三种方法hasNext、next和remove)
    private class LinkedListIterator implements java.util.Iterator<AnyType> {
        private Node<AnyType> current = beginMarker.next;   //当前位置
        /**(之所以要记录这个是因为:为避免迭代器准备给出某一项作为下一项nextItem,而该项以后可能被删除,或者一个新的项正好插入在该项的前面,所以必须要记住这些更改法则)**/
        private int expectedModCount = modCount;    //检查modCount是否正确
        private boolean okToRemove = false;

        @Override
        public boolean hasNext() {
            return current != endMarker;
        }

        @Override
        public AnyType next() { //返回节点的值,然后向后继续推进current
            if(modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if(!hasNext())
                throw new NoSuchElementException();

            AnyType nextItem = current.data;
            current = current.next;
            okToRemove = true;
            return nextItem;
        }

        public void remove(){
            if(modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if(!okToRemove)
                throw new IllegalStateException();

            MyLinkedList.this.remove(current.prev);
            expectedModCount++; //如果迭代器调用了自己的remove方法,那么这个迭代器仍然是合法的,因为expectedModCount同步更新了
            okToRemove = false;
        }
    }
    public static void main(String[] args) {
        //test()
    }

}

 

posted @ 2020-12-24 21:39  Peterxiazhen  阅读(182)  评论(0编辑  收藏  举报