java实现ArrayList和LinkedList[包含接口List和抽象类AbstractList]

java实现ArrayList和LinkedList[包含接口List和抽象类AbstractList]

图解

在这里插入图片描述

首先我们需要定义一个MyList的接口,将ArrayList和LinkedList共同的方法进行定义
package com.bingym.list.mylist;

public interface MyList<E> {
    //自定义List接口:内部包含了List的抽象方法
    int size();//获取集合的大小

    boolean isEmpty();//是否为空

    boolean contains(E element);//是否包含

    boolean add(E element);//添加元素:返回true

    E get(int index);//获取元素

    E set(int index,E element);//设置元素

    void add(int index, E element);//指定索引添加元素

    E remove(int index);//根据索引删除元素

    int indexOf(E element);//是否包含该索引

    void clear();//清空

    String toString();
}

定义抽象类MyAbstractList:实现共性的方法
package com.bingym.list.myabstractlist;

import com.bingym.list.mylist.MyList;

public abstract class MyAbstractList<E> implements MyList<E> {
    //定义抽象类MyAbstractList
    //抽出ArrayList和LinkedList共同的方法
    //定义属性:集合的大小
    protected int size;

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

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

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

实现MyArrayList类
package com.bingym.list.myarraylist;

import com.bingym.list.myabstractlist.MyAbstractList;

public class MyArrayList<E> extends MyAbstractList<E> {
    //定义数组,用来存储集合的元素
    private Object[] elementData;
    //定义变量,用来记录数组的个数:父类已经实现
    //private int size;
    //定义空数组,用来在创建集合对象的时候给elementData初始化
    private Object[] emptyArray = {};
    //定义常量,用来记录集合的常量
    private final int DEFAULT_CAPACITY = 10;

    //构造方法
    public MyArrayList() {
        //给elementData初始化
        elementData = emptyArray;
    }

    //定义add方法
    public boolean add(E e) {
        //调用之前需要判断是否需要进行扩容
        grow();
        //将元素添加到集合:即elementData数组中
        elementData[size++] = e;
        return true;
    }

    //定义简单扩容的方法
    private void grow() {
        //判断集合存储元素的数组是否等于emptyArray
        if (elementData == emptyArray) {
            //此时集合为空集合{}
            //则第一次扩容:将其长度置为10
            elementData = new Object[DEFAULT_CAPACITY];
        }
        //如果不是空集合,即进行当前集合长度的1.5倍进行扩容处理
        if (size == elementData.length) {
            //当前元素的个数已经等于当前集合的长度
            //先定义变量记录集合的老容量
            int oldCapacity = elementData.length;
            //进行扩容处理
            int newCapacity = oldCapacity + (oldCapacity >> 1);//右移1位等价于oldCapacity/2
            //创建一个新的长度的数组
            Object[] obj = new Object[newCapacity];
            //然后将老数组的元素拷贝放新数组中
            //从elementData拷贝到obj中
            System.arraycopy(elementData,0,obj,0,elementData.length);
            elementData = obj;
        }
    }

    //校验索引是否越界的方法
    private void checkIndex(int index) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("索引越界");
        }
    }

    //获取集合的长度
    //父类已经编写

    //根据索引获取元素
    public E get(int index) {
        //调用checkIndex方法校验索引是否越界
        checkIndex(index);
        //直接从集合的数组中获取元素并返回
        return (E) elementData[index];
    }

    //修改集合元素内容的方法
    public E set(int index,E element) {
        //checkIndex方法校验索引是否越界
        checkIndex(index);
        //把当前修改的index的元素取出来
        E value = (E) elementData[index];
        //替换元素
        elementData[index] = element;
        //将老元素内容返回
        return value;
    }

    @Override
    public void add(int index, E element) {
        checkIndex(index);
        grow();
        for (int i = size - 1; i >= index; i--) {
            elementData[i + 1] = elementData[i];//将index后面的元素向后移动
        }
        elementData[index] = element;
        size++;
    }

    //根据索引删除当前元素的方法
    public E remove(int index) {
        //校验索引
        checkIndex(index);
        //取出当前索引的值
        E value = (E) elementData[index];
        //计算需要移动的个数
        int numMoved = size - index - 1;
        //判断移动的个数是否大于0
        if (numMoved > 0) {
            System.arraycopy(elementData,index+1,elementData,index,numMoved);
        }
        //将最后一个位置元素置为null,尽快被垃圾回收机制回收
        elementData[--size] = null;
        return value;//返回要删除的元素
    }

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

    @Override
    public void clear() {
        //集合清空方法
        for (int i = 0; i < size; i++) {
            elementData[i] = null;
        }
        //注意:将size置为0
        size = 0;
    }

    //toString方法
    public String toString() {
        //对集合进行判断:若为空,返回"[]"
        if (size == 0) {
            return "[]";
        }
        //不为空,创建StringBuilder进行集合元素的拼接
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        //循环遍历数组
        for (int i = 0; i < size; i++) {
            if (i == size-1) {
                //到达集合的最后一个元素
                sb.append(elementData[i]).append("]");
            }else {
                sb.append(elementData[i]).append(",").append(" ");
            }
        }
        //将sb转换成字符窗进行返回
        return sb.toString();
    }
}

实现单向链表类
package com.bingym.list.mylinkedlist;

import com.bingym.list.myabstractlist.MyAbstractList;

public class MySingleLinkedList<E> extends MyAbstractList<E> {

    //单向链表:内部包含一个Node节点的内部类(包含节点的data域和next域),还需要单向链表的大小size(父类已经定义),以及一个头结点first
    private Node first;//头结点,默认为null
    private static class Node<E> {
        //data域
        E element;
        //next域
        Node<E> next;

        public Node(E element, Node<E> next) {
            this.element = element;
            this.next = next;
        }
    }

    @Override
    public boolean add(E element) {
        //找到链表的最后一个节点
        Node<E> x = first;//定义辅助变量
        Node<E> node = new Node<>(element,null);
        if (isEmpty()) {
            first = new Node(element,first);
            size++;
            return true;
        }
        //找到添加节点的位置
        while(true) {
            if (x.next == null) {
               break;
            }
            x = x.next;
        }
        //此时x为当前链表的最后一个节点
        x.next = node;
        size++;
        return true;

        //以上代码等同于在index为size的位置添加元素
        //add(size,element);
    }

    @Override
    public E get(int index) {
        //根据index值获取指定元素的值,即节点的data域(element)
        //由于链表不存在索引,此处的index表示的是链表从头结点开始遍历查找的次数
        //首先需要判断当前的index存不存在越界问题:若越界,直接报越界异常
        checkIndex(index);
        return node(index).element;
    }

    private Node<E> node(int index) {
        //根据index将链表从first节点向后平移index次
        //由于头节点first不能改变,这里定义一个辅助指针变量,指向first
        Node<E> x = first;
        for (int i = 0; i < index; i++) {
            x = x.next;
        }
        //此时x即为需要get的节点
        return x;
    }

    @Override
    public E set(int index, E element) {
        //set方法的返回值为原来的老值
        //首先我们依旧需要校验index
        checkIndex(index);
        //获取当前index对应的节点
        Node<E> node = node(index);
        //获取老值
        E oldElement = node.element;
        //修改node的data域为新的element
        node.element = element;
        return oldElement;
    }

    @Override
    public void add(int index, E element) {
        //根据index值添加节点
        //先校验索引是否越界
        checkPostionIndex(index);
        if (index == 0) {
            first = new Node(element,first);//next为null
        }else {
            //先获取index-1的节点
            Node<E> pre = node(index - 1);
            //在获取index的节点
            Node<E> next = node(index);
            //创建一个新的节点
            Node<E> node = new Node<>(element,next);//next域为之前index位置的节点
            pre.next = node;//将pre的next指向现在添加的新的index位置的节点
        }
        size++;//记得将size加1
    }

    @Override
    public E remove(int index) {
        //校验index
        checkPostionIndex(index);
        //定义辅助指针变量
        Node<E> oldNode = first;
        if (index == 0) {
            first = first.next;//若删除的是头节点
        }else {
            Node<E> pre = node(index - 1);//获取index前一个节点
            oldNode = pre.next;
            //将index的前一个节点的next域指向index的next域,即跳过index节点
            pre.next = oldNode.next;
        }
        size--;//记得将size减1
        //最后返回原index位置的节点的元素element
        return oldNode.element;
    }

    @Override
    public int indexOf(E element) {
        //查找当前data对应的索引
        //即当前链表是否存在element元素
        Node<E> x = first;//定义辅助指针变量
        int index = 0;
        if (element == null) {
            //若element为空
            for (Node i = x;i != null;i = i.next) {
                if (element == i.element) {
                    return index;
                }
                index++;
            }
        }else {
            //若element不为空
            for (Node i = x;i != null;i = i.next) {
                if (element.equals(i.element)) {
                    return index;
                }
                index++;
            }
        }
        //若没有找到,则表示集合中不存在该element,返回-1
        return -1;
    }

    @Override
    public void clear() {
        //将头节点置为null
        first = null;
        //将单向链表的size置为0
        size = 0;

    }
    //校验索引是否越界的方法
    private void checkIndex(int index) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("索引越界");
        }
    }

    //更加高大上的校验索引是否越界的方法
    private void checkPostionIndex(int index) {
        if(!isPostionIndex(index)){
            throw new IndexOutOfBoundsException(": Index: " + index + ", Size: " + size);
        }
    }

    private boolean isPostionIndex(int index) {
        return index >= 0 && index <= size;
    }

    //重写toString方法
    public String toString(){

        if(size == 0){
            return  "[]";
        }
        StringBuilder sb = new StringBuilder().append("[");
        Node x = first;
        for(Node i = x; i != null ; i = i.next){
            sb.append(i.element);
            if( i.next == null){
                return sb.append("]").toString();
            }
            sb.append(",");
        }
        return  sb.toString();
    }
}

实现双向链表类
package com.bingym.list.mylinkedlist;

import com.bingym.list.myabstractlist.MyAbstractList;

public class MyDoubleLinkedList<E> extends MyAbstractList<E> {
    //双向链表实现
    //在单向链表的基础上:存在头结点first和尾节点last
    //Node节点类:pre(前向节点),data域(element),next(后向节点)
    //定义双线链表的头节点和尾节点
    private Node<E> first;
    private Node<E> last;

    private static class Node<E> {
        E element;
        Node<E> pre;
        Node<E> next;

        public Node(E element, Node<E> pre, Node<E> next) {
            this.element = element;
            this.pre = pre;
            this.next = next;
        }
    }

    @Override
    public boolean add(E element) {
        add(size,element);
        return true;
    }

    @Override
    public E get(int index) {
        //根据index值获取指定元素的值,即节点的data域(element)
        //由于链表不存在索引,此处的index表示的是链表从头结点开始遍历查找的次数
        //首先需要判断当前的index存不存在越界问题:若越界,直接报越界异常
        checkElementIndex(index);
        return node(index).element;
    }

    //获取当前index指向的节点
    private Node<E> node(int index) {
        Node x = first;//定义辅助变量
        //先判断我们需要查找的index是更靠近尾部还是更靠近头部
        if (index > size >> 1) {
            //即index超过了size的一半:则表示index更靠近尾部
            x = last;
            for (int i = size - 1;i > index;i--) {
                x = x.pre;
            }
        }else {
            //即index未超过了size的一半:则表示index更靠近头部
            for (int i = 0;i < index;i++) {
                x = x.next;
            }
        }
        return x;
    }


    @Override
    public E set(int index,E element) {
        //set方法的返回值为原来的老值
        //首先我们依旧需要校验index
        checkIndex(index);
        //获取当前index对应的节点
        Node<E> node = node(index);
        //获取老值
        E oldElement = node.element;
        //修改node的data域为新的element
        node.element = element;
        return oldElement;
    }

    @Override
    public void add(int index, E element) {
        //根据index位置来添加节点元素
        //校验index
        checkPostionIndex(index);
        //如果此时index为链表的末尾
        if (index == size) {
            linkLast(element);//在链表的末尾或者没有元素时添加元素
        }else {
            linkBefore(element,node(index));
        }
        size++;
    }

    private void linkBefore(E element, Node<E> node) {
        Node<E> pre = node.pre;//找到index对应的位置的节点的前节点
        Node<E> newNode = new Node<>(element,pre,node);//以pre为前节点,index对应的节点为next节点
        node.pre = newNode;
        if (pre == null) {  //说明在index=0的位置的添加元素
            first =newNode;
        }else {
            pre.next = newNode;
        }

    }

    private void linkLast(E element) {
        //1.拿到last节点
        //2.构建node完成它的指向关系
        //3.将原来的last节点的next域指向新构建的node节点(即我们需要添加的节点)
        //4.将链表的last进行修改
        Node<E> lastNode = last;
        Node<E> newNode = new Node<>(element,lastNode,null);
        last = newNode;
        if (lastNode == null) {
            first = newNode;//链表没有元素first = last = null;
        }else {
            lastNode.next = newNode;//添加至末尾
        }
    }

    @Override
    public E remove(int index) {    // index >= 0 && index <  size
        //校验index
        checkElementIndex(index);
        //先拿到index对应的节点
        Node<E> node = node(index);
        //分别达到index对应节点的前一个节点和后一个节点
        Node<E> pre = node.pre;
        Node<E> next = node.next;
        if (pre == null) {//index==0的情况
            first = next;
            next.pre = null;
        }else {
            pre.next = next;
        }
        if (next == null) {//index==size-1的情况
            last = pre;
            pre.next = null;
        }else {
            next.pre = pre;
        }

        //记得size--
        size--;
        return node.element;
    }

    @Override
    public int indexOf(E element) {
        Node x = first;
        int index = 0;
        if (element == null) {

            for (Node i = x; i != null; i = i.next) {
                if (element == i.element) {
                    return index;
                }
                index++;
            }
        } else {
            for (Node i = x; i != null; i = i.next) {
                if (element.equals(i.element)) {
                    return index;
                }
                index++;
            }
        }
        return -1;
    }

    @Override
    public void clear() {
        size = 0;
        // help gc
        first = null;
        last = null;
    }

    //校验索引是否越界的方法
    private void checkIndex(int index) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("索引越界");
        }
    }

    //更加高大上的校验索引是否越界的方法
    private void checkPostionIndex(int index) {
        if(!isPostionIndex(index)){
            throw new IndexOutOfBoundsException(": Index: " + index + ", Size: " + size);
        }
    }

    private boolean isPostionIndex(int index) {
        return index >= 0 && index <= size;
    }

    private void checkElementIndex(int index) {

        if (!isElementIndex(index)) {
            throw new IndexOutOfBoundsException(": Index: " + index + ", Size: " + size);
        }

    }

    private boolean isElementIndex(int index) {
        // 满足条件
        return index >= 0 && index < size;

    }

    //toString方法
    public String toString() {

        if (size == 0) {
            return "[]";
        }
        StringBuilder sb = new StringBuilder().append("[");
        Node x = first;
        for (Node i = x; i != null; i = i.next) {
            sb.append(i.element);
            if (i.next == null) {
                return sb.append("]").toString();
            }
            sb.append(",");
        }
        return sb.toString();
    }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值