分析 + 手写 LinkedList 源码(增删查询)

首先 LinkedList 的底层实现其实是一个双向链表,这个是最主要的,在后面的add、get、remove 都会用到这个原理。

下面是我的手写源码,代码中有注释,我运行了下,应该没有问题,如果有问题,请指出,我会改进,谢谢!

/**
 * @description: 实现 LinkedList 基本的增删查询
 * @author: Rule
 * @date: 2018-09-09 18:14
 **/
public class TestLinkedList<E> {

    // 双向链表使用的实际长度
    transient int size = 0;

    // 链表的头节点
    transient Node first;

    // 链表的尾节点
    transient Node last;

    // 用于遍历时,记录遍历的次数
    private int nextIndex;

    //节点的信息 双向链表包括上一个节点和下一个节点的信息,而且还包括该节点的值
    private static class Node<E>{
        private E item;
        private Node<E> prev;
        private Node<E> next;
    }

    //无参构造函数
    public TestLinkedList(){

    }


    //添加操作 (不含下标)
    public void add(E e){
        //new node 来保存添加信息
        Node<E> node = new Node<>();
        node.item = e;
        //如果头节点为空,则说明该链表现在是空链表
        if (first == null){
            first = node;
            last = first;
        }else {
            //头节点不会空
            last.next = node;
            node.prev = last;
            last = node;
        }
        //实际长度++
        size++;
    }


    //添加操作 (含下标)
    public void add(int index, E e){
        //checkIndex 中没有考虑在size处添加(即末尾处)
        Node<E> newNode = new Node<>();
        newNode.item = e;
        //首先要查询该下标是否有值
        Node<E> oldNode = getNode(index);
        if (oldNode == null) {
            //olcNode == null 说明该链表要么是空链表,要么是在末尾添加数据

            if(index == 0) {
                //在首部添加数据
                first = newNode;
                last = first;
            }else {
                //在末尾添加数据
                last.next = newNode;
                newNode.prev = last;
                last = newNode;
            }
        }else {

            if (index == 0) {
                //在链表的首部插入
                first.prev = newNode;
                newNode.next = first;
                first = newNode;
            } else {
                //检查 index 是否合法
                checkIndex(index);
                //得到当前下标的 node
                //  Node<E> oldNode = getNode(index);
                oldNode.prev.next = newNode;
                newNode.prev = oldNode.prev;
                oldNode.prev = newNode;
                newNode.next = oldNode;
            }
        }
        size++;
    }


    //根据下标元素删除
    public void remove(int index){
        //首先进行检查下标是否合法
        checkIndex(index);
        //查找到需要删除的节点信息
        Node<E> oldNode = getNode(index);
        //System.out.println("index = " + index);
        //System.out.println("size = " + size);
        if (index == 0){
            first = oldNode.next;
            first.prev = null;
        }else if (index == size - 1){
            last = oldNode.prev;
            last.next = null;
        }else {
            oldNode.prev.next = oldNode.next;
            oldNode.next.prev = oldNode.prev;
        }
        size--;
    }


    //得到下标节点的值
    public E get(int index){
        return (E) getNode(index).item;
    }


    //查询得到节点 (从 first 节点往后逐个遍历)
    public Node getNode(int index){
        if (index != 0){
            //首先检查 index 是否合法
            checkIndex(index);
        }
        Node node = first;
        nextIndex = 0;
        while(hasNext()){
            if (nextIndex == index){
                return node;
            }
            nextIndex++;
            node = node.next;
        }
        return  null;
    }

    private void checkIndex(int index) {
        if (index < 0 || index >= size){
            throw new IndexOutOfBoundsException("index 越界啦!!");
        }
    }

    //遍历元素是否结束
    private boolean hasNext() {
       return nextIndex < size;
    }


}

猜你喜欢

转载自blog.csdn.net/LarrYFinal/article/details/82559052