浅谈Java集合框架之List、ArrayList、LinkedList的使用及实现

1.List

List是一个接口继承于Collection接口,数据结构上List代表的是一个线性表
那么对于List接口中的方法有:

  • boolean add(E e) :尾插
  • void add(int index, E element) :将 e 插入到 index 位置,同时index之后的元素,必须逻辑向后移
  • E remove(int index):删除 index 位置元素,同时,index之后的所有元素必须逻辑前移
  • boolean remove(Object o) :删除遇到的第一个o元素(本质上是使用equals进行比较)
  • E get(int index):获取下标 index 位置元素
  • E set(int index, E element) :将下标index位置元素设置为element
  • int size():返回元素个数
  • void clear():清空线性表
  • boolean isEmpty():返回是否是一个空的线性表
  • boolean contains(Object o):判断o是否在线性表中(本质上是使用equals进行比较)
  • int indexOf(Object o) :返回第一个o所在下标(本质上是使用equals进行比较)
  • int lastIndexOf(Object o):返回最后一个o的下标(本质上是使用equals进行比较)
  • List < E > subList(int fromIndex, int toIndex):截取部分list,不会影响原来的线性表
  • sort (Comparator <?super E>c):对线性表进行排序,根据传入的比较器排序,可以使用匿名内部类
  • iterator():返回迭代器,进行从前往后的遍历
  • listIterator():效果等同于listIterator(0)
  • listIterator(int index):从index位置开始遍历,下标的计算特殊一点
  • toArray()系列:list转数组
  • Arrays.asList():数组转list

对于方法使用的注意:

  • remove:如果是 Integer 类型,则remove(int)就是当下标使用,返回删除的元素。如果是remove((Integer)int),则当元素使用,返回boolean值
  • 对于引用类型的删除,需要在类中重写equals方法
  • 所有的ArrayList或者List其实都可以看做Collection

2. ArrayList

ArrayList 是一个顺序表,是容器,实现了List接口,通过泛型表现变化的元素类型。
除了继承到的方法,ArrayList增加的额外方法有:

  • ArrayList():无参构造
  • ArrayList(Collection<? extends E> c) :利用其他 Collection 构建ArrayList
  • ArrayList(int initialCapacity):指定顺序表初始容量

对ArrayList进行手动的实现:

2.1 仿写真实的List接口

/**
 * 仿写真实的List
 */
public interface List extends Iterable{

    //添加元素
    boolean add(Integer e);

    void add(int index,Integer e);

    //根据下标删除
    Integer remove(int index);
    //根据元素删除
    boolean remove(Integer e);
    //删除第一个遇到的
    Integer get(int index);

    Integer set(int index,Integer e);

    int size();
    void clear();
    boolean isEmpty();

    //包含
    boolean contains(Integer e);

    int indexOf(Integer e);

    int lastIndexOf(Integer e);
}

2.2 仿写真实的ArrayList

public class ArrayList implements List {

    private int[] array;//数组
    private int size;//元素个数

    private int capacity;
    public ArrayList(){
        this.capacity=10;
        this.array = new int[this.capacity];
        this.size=0;
    }
    public ArrayList(int capacity) {
        this.capacity = capacity;
        this.array = new int[capacity];
        this.size=0;
    }

    public ArrayList(List other){
        array = new int[other.size()];
        for(int i=0;i<other.size();i++){
            array[i] = other.get(i);
        }
        this.size = other.size();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("[");
        for(int i=0;i<this.size;i++){
            if(i==this.size-1){
                sb.append(array[i]);
            }else{
                sb.append(array[i]+", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * 扩容
     * 时间复杂度O(n)
     */
    public void dilatation(){
        if(this.size==this.capacity){
            this.capacity*=2;
            //定义新数组 并将老数组内容搬到新数组
            int[] newArray =  Arrays.copyOf(this.array,this.capacity);
            this.array = newArray;
        }
    }
    /**
     * 时间复杂度:平均 O(1)
     * @param e
     * @return
     */
    @Override
    public boolean add(Integer e) {
        dilatation();
        this.array[size++] = e;
        return true;
    }

    /**
     * 时间复杂度:O(n)
     *要把index及之后的所有元素,全部向后移
     * 为了元素不被覆盖,从后往前搬
     * @param index
     * @param e
     */
    @Override
    public void add(int index, Integer e) {
        if(index<0 || index>this.size){
            throw new IndexOutOfBoundsException("下标不合法!");

        }
        dilatation();
        for(int i=this.size;i>index;i--){
            array[i] = array[i-1];
        }
        array[index] = e;
        size++;
    }

    /**
     * 时间复杂度:O(n)
     * 从后往前覆盖
     * @param index
     * @return
     */
    @Override
    public Integer remove(int index) {
        if(index<0 || index>=this.size){
            throw new IndexOutOfBoundsException("下标不合法!");
        }
        int e = array[index];
        for(int i = index;i<this.size-1;i++){
            array[i] = array[i+1];
        }
        this.size--;
        return e;
    }

    /**
     * 时间复杂度:O(n)
     * @param e
     * @return
     */
    @Override
    public boolean remove(Integer e) {

        int index = indexOf(e);
        if(index!=-1){
            remove(index);
            return true;
        }else{
            return false;
        }

    }

    /**
     * 时间复杂度:O(1)
     * @param index
     * @return
     */
    @Override
    public Integer get(int index) {
        if(index<0||index>=this.size){
            throw new IndexOutOfBoundsException("下标不合法!");
        }
        return array[index];
    }

    /**
     * 时间复杂度:O(1)
     * @param index
     * @param e
     * @return
     */
    @Override
    public Integer set(int index, Integer e) {
        if(index<0||index>=this.size){
            throw new IndexOutOfBoundsException("下标不合法!");
        }
        Integer oldData = array[index];
        array[index] = e;
        return oldData;
    }

    /**
     * 时间复杂度:O(1)
     * @return
     */
    @Override
    public int size() {
        return this.size;
    }

    /**
     * 时间复杂度:O(n)
     */
    @Override
    public void clear() {
        //-1代表无效值
        Arrays.fill(array,-1);
        this.size=0;
    }

    /**
     * 时间复杂度:O(1)
     * @return
     */
    @Override
    public boolean isEmpty() {
        return this.size==0;
    }

    /**
     * 时间复杂度:O(n)
     * @param e
     * @return
     */
    @Override
    public boolean contains(Integer e) {

        return indexOf(e)!=-1;
    }

    /**
     * 时间复杂度:O(n)
     * @param e
     * @return
     */
    @Override
    public int indexOf(Integer e) {
        for(int i=0;i<this.size;i++){
            if(array[i]==e){
                return i;
            }
        }
        return -1;
    }

    /**
     * 时间复杂度:O(n)
     * @param e
     * @return
     */
    @Override
    public int lastIndexOf(Integer e) {
        for(int i=this.size-1;i>=0;i--){
            if(array[i]==e){
                return i;
            }
        }
        return -1;
    }

    @Override
    public Iterator iterator() {
        //返回一个Iterator接口的实现类的对象
        return new ArrayListIterator(this);
    }
}

2.3 仿写真实的Iterator接口(迭代器)

  • 迭代器互相之间独立
  • 迭代遍历的同时,不允许修改list的结构
  • 如果确实需要删除,需要使用迭代器中的remove方法,可以删除当前迭代到的位置
/**
 * 仿写真实的Iterator接口
 * 迭代器
 */
public interface Iterator {
	//返回true,表示本次迭代还没有把所有的数据遍历完
    boolean hasNext();
    //返回要遍历的下一个元素
    Integer next();
    void remove();
}

2.4 仿写真实的Iterable接口

iterate迭代,一个一个遍历

  • 如果一个类实现了Iterable接口,则表示这个类具备迭代的能力,隐含着,这个类的对象实际上表示一个容器
  • 该类通过返回一个迭代器(Iterator),可以通过这个迭代器进行容器内的元素的迭代
/**
 * 仿写真实的Iterable接口
 * 具备迭代能力 使用了依赖了Iterator接口
 */
public interface Iterable {
    Iterator iterator();
}

2.5 Iterator的实现类ArrayListIterator

/**
Iterator的实现类 用于给ArrayList中传递
*/
public class ArrayListIterator implements Iterator{
    private int index;
    private ArrayList list;
    //对一个顺序表做迭代,关键是控制下标


    public ArrayListIterator(ArrayList list) {
        this.index = 0;
        this.list = list;
    }

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

    @Override
    public Integer next() {
        return list.get(index++);
    }

    @Override
    public void remove() {
        //TODO
    }
}

2.6 泛型的ArrayList

重点对于构造方法、两种toArray方法、indexOf、clear进行实现

/**
 * 泛型的ArrayList
 * clear或者其他删除的时候,除了修改size,一定要把从List中删除掉的元素置为null,以免内存泄露
 * contains/indexOf/lastIndexOf等方法,都随时可能调用元素的equals方法
 * toArray的两种实现
 */
public class MyArrayList<E> implements List<E> {
    private E[] array;
    private int size;

    public MyArrayList() {
        //无法直接定义泛型数组,所以只能定义Object类型数组 然后强转
        this.array = (E[])new Object[10];
        this.size = 0;
    }
    @Override
    public int size() {
        return this.size;
    }

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

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

    @Override
    public Iterator<E> iterator() {
        return null;
    }

    /**
     *
     * @return
     */
    @Override
    public Object[] toArray() {
        Object[] a = new Object[size];
        for(int i=0;i<this.size;i++){
            a[i] = array[i];
        }
        return a;
    }

    /**
     * 传进来的数组 长度小于size创建一个新数组返回
     * 大于size将元素放进去,并将size处元素置为null
     * 等于size,将元素放进去返回
     * @param a
     * @param <T>
     * @return
     */
    @Override
    public <T> T[] toArray(T[] a) {
        if(a.length<size){
            //创建一个数组直接返回
            T[] newArray = (T[])new Object[size];
            for(int i=0;i<size;i++){
                newArray[i] = (T)array[i];
            }
            return newArray;
        }else if(a.length==size){
            //把元素放入并返回

            for(int i=0;i<size;i++){
                a[i] = (T)array[i];
            }
            return a;
        }else{
            //把元素放入并返回
            //把超过的第一个位置设置为null
            for(int i=0;i<size;i++){
                a[i] = (T)array[i];
            }
            a[size] = null;
            return a;
        }

    }

    @Override
    public boolean add(E e) {

        array[size++] = e;
        return true;
    }

    @Override
    public boolean remove(Object o) {
        int i = indexOf(o);

        if(i==-1){
            return false;
        }else{
            remove(i);
            return true;
        }

    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        return false;
    }

    @Override
    public boolean addAll(int index, Collection<? extends E> c) {
        return false;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return false;
    }

    @Override
    public void clear() {
        //如果是基本类型,数组中元素是否需要清理成无效值其实无所谓
        //但如果是引用类型,必须把数组中的元素修改为null,这样不会内存泄露
        Arrays.fill(array,null);
        this.size=0;
    }

    @Override
    public E get(int index) {
        return array[index];
    }

    @Override
    public E set(int index, E element) {
        E oldData = array[index];
        array[index] = element;
        return oldData;
    }

    @Override
    public void add(int index, E element) {

    }

    @Override
    public E remove(int index) {
        return null;
    }

    /**
     *
     * @param o
     * @return
     */
    @Override
    public int indexOf(Object o) {
        for(int i=0;i<this.size;i++){
            if(o==null){
                if(array[i]==o){
                    return i;
                }
            }else{
                if(array[i].equals(o)){
                    return i;
                }
            }
        }
       return -1;
    }

    @Override
    public int lastIndexOf(Object o) {
        return 0;
    }

    @Override
    public ListIterator<E> listIterator() {
        return null;
    }

    @Override
    public ListIterator<E> listIterator(int index) {
        return null;
    }

    @Override
    public List<E> subList(int fromIndex, int toIndex) {
        return null;
    }
}

3. LinkedList

List的实现类,数据结构是链表(双向链表,记录了第一个和最后一个节点)
除了继承的方法外,新增的方法只有一个无参的构造方法

对于LinkedList的手动实现:前面的List接口、Iterator接口、Iterable接口直接使用

3.1 节点类(Node)

public class Node {
   public Node prev;
   public Node next;
   public Integer element;

    public Node(Integer element) {
        this.element = element;
    }
}

3.2 仿写真实的LinkedList

public class LinkedList implements List{

    public Node head; //指向第一个节点
    public Node last;//指向最后一个节点
    public int size;

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("[");
        for(Node cur = this.head;cur!=null;cur = cur.next){
            sb.append(cur.element);
            if(cur!=last){
                sb.append(", ");
            }
        }
        sb.append("]");

        return sb.toString();

    }

    /**
     * 尾插   时间复杂度 O(1)
     * @param e
     * @return
     */
    @Override
    public boolean add(Integer e) {

        Node node = new Node(e);

        if(size==0){//判空
            this.head = this.last = node;

        }else{
            this.last.next = node;
            node.prev = this.last;
            this.last = node;
        }
        size++;
        return true;
    }

    /**
     * O(n)
     * @param index
     * @param e
     */
    @Override
    public void add(int index, Integer e) {
        if(index<0 || index>size){
            throw new IndexOutOfBoundsException("下标越界!");
        }
        Node node = new Node(e);
        //index==0 头插
        if(index==0){
            if(this.size==0){
                this.head = node;
                this.last = node;
            }else{
                node.next = this.head;
                this.head.prev = node;
                this.head = node;
            }
            this.size++;
            return;
        }else if(index==this.size){ //index==size 调用尾插
            add(e);
        }else{
            //中间插入
            //跳index不部找插入位置,也可以跳index-1步找前驱位置
            Node cur = null;
            if(index<size/2){
                cur = this.head;
                while(index>0){
                    cur = cur.next;
                    index--;
                }
            }else{
                cur = this.last;
                while(this.size-1-index>0){
                    cur = cur.prev;
                    index++;
                }
            }
            node.next = cur;
            cur.prev.next = node;
            node.prev = cur.prev;
            cur.prev = node;

            this.size++;
        }

    }

    /**
     * O(n)
     * @param index
     * @return
     */
    @Override
    public Integer remove(int index) {
        if(index<0 || index>=this.size){
            throw  new IndexOutOfBoundsException("下标非法!");
        }
        Integer v = 0;
        //index==0 头删
        if(index==0){
            if(this.head!=null&&this.head.next==null){
                v = this.head.element;
                this.head = null;
                this.last = null;

            }else{
                v = this.head.element;
                this.head = this.head.next;
                this.head.prev = null;
            }
            size--;

        }else if(index==this.size-1){// 尾删
            v = this.last.element;
            this.last = this.last.prev;
            this.last.next = null;
            size--;
            if(size==0){
                head=null;
            }
        }else{
            Node cur = null;
            if(index<size/2){
                cur = this.head;
                while(index>0){
                    cur = cur.next;
                    index--;
                }
            }else{
                cur = this.last;
                while(this.size-1-index>0){
                    cur = cur.prev;
                    index++;
                }
            }
            v = cur.element;
            cur.prev.next = cur.next;
            cur.next.prev = cur.prev;
            size--;
        }
        return v;
    }

    /**
     * O(n)
     * @param e
     * @return
     */
    @Override
    public boolean remove(Integer e) {
        for(Node cur = this.head;cur!=null;cur = cur.next){
            if(cur.element.equals(e)){
                if(cur.prev==null){
                    remove(0);
                }else if(cur.next==null){
                    remove(this.size-1);
                }else{
                    cur.prev.next = cur.next;
                    cur.next.prev = cur.prev;
                    size--;
                }
                return true;
            }
        }
        return false;
    }

    /**
     * O(n)
     * @param index
     * @return
     */
    @Override
    public Integer get(int index) {
        if(index<0 || index>=this.size){
            throw  new IndexOutOfBoundsException("下标非法!");
        }
        Node cur = this.head;
        for(int i=0;i<this.size;i++){
            cur = cur.next;
        }
        return cur.element;
    }

    /**
     * O(n)
     * @param index
     * @param e
     * @return
     */
    @Override
    public Integer set(int index, Integer e) {
        if(index<0 || index>=this.size){
            throw  new IndexOutOfBoundsException("下标非法!");
        }
        Node cur = this.head;
        for(int i=0;i<this.size;i++){
            cur = cur.next;
        }
        Integer v = cur.element;
        cur.element = e;
        return v;
    }

    /**
     * O(1)
     * @return
     */
    @Override
    public int size() {
        return this.size;
    }

    @Override
    public void clear() {
        this.head = this.last = null;
        this.size = 0;
    }

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

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

    /**
     * O(n)
     * @param e
     * @return
     */
    @Override
    public int indexOf(Integer e) {
        Node cur = this.head;
        int index=0;
        while(cur!=null){
            if(cur.element.equals(e)){
                return index;
            }
            index++;
            cur = cur.next;
        }
        return -1;
    }

    /**
     * O(n)
     * @param e
     * @return
     */
    @Override
    public int lastIndexOf(Integer e) {
        Node cur = this.last;
        int index=0;
        while(cur!=null){
            if(cur.element.equals(e)){
                return this.size-index-1;
            }
            index++;
            cur = cur.prev;
        }
        return -1;
    }

    @Override
    public Iterator iterator() {
    	//返回一个Iterator的实现类
        return new LinkedListIterator(this);
    }
}

3.3 Iterator的实现类LinkedListIterator

public class LinkedListIterator implements Iterator{
    private LinkedList list;
    private Node cur;

    public LinkedListIterator(LinkedList list) {
        this.list = list;
        this.cur = list.head;
    }

    @Override
    public boolean hasNext() {
        return cur!=null;
    }

    @Override
    public Integer next() {
        Integer v = cur.element;
        cur = cur.next;
        return v;
    }

    @Override
    public void remove() {
        //TODO
    }
}

4. ArrayList 和LinkedList的区别

从以下几方面考虑:

  • 每个方法做什么用,参数列表和返回值是什么
  • 大概描述每个方法的具体实现
  • 每个方法的时间复杂度
  • 有些方法有部分特殊点
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值