深入理解Java集合框架之实现LinkedList

参考文章:JCFInternals
环境:JDK1.9

介绍:
LinkedList同时实现了List接口和Deque接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(Stack),LinkedList底层通过双向链表实现,允许放入 null,未实现同步。

实现功能:

  • size():得到当前集合元素个数
  • isEmpty():判断集合是否为空
  • get(int index):获得指定位置集合
  • set(int index, T element):将指定位置集合设置为指定值
  • add(T element):向集合添加一个元素
  • add(int index, T element):向集合指定下标添加指定元素
  • remove(int index):移除指定下标的元素
  • remove(Object o):移除集合中第一次出现的指定元素

代码:

public class MyLinkedList<T> {

    int size;

    // 链表的第一个元素
    Node<T> first;

    // 链表的最后一个元素
    Node<T> last;

    public int size() {
        return size;
    }

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

    // 定义链表结点
    private static class Node<T> {
        T item;
        Node<T> prev;
        Node<T> next;

        public Node(Node<T> prev, T item, Node<T> next) {
            this.item = item;
            this.prev = prev;
            this.next = next;
        }
    }

    public boolean add(T element) {
        // 找到末尾指针
        final Node<T> l = last;
        final Node<T> newNode = new Node(l, element, null);
        last = newNode;
        // 如果当前链表为空,则 newNode 为第一个结点
        if (l == null) {
            first = newNode;
        } else {
            l.next = newNode;
        }
        size++;
        return true;
    }

    public void add(int index, T element) {
        // 范围检查
        checkPositionIndex(index);

        // 如果是最后一个插入
        if (index == size) {
            add(element);
        } else {
            // 找到 index 位置的链表
            final Node<T> cur = node(index);
            // 修改引用
            // 1. 要插入的新结点是 newNode
            // 2. newNode 的前一结点是 pred
            // 3. newNode 的后一结点是 cur
            final Node<T> pred = cur.prev;
            final Node<T> newNode = new Node(pred, element, cur);
            cur.prev = newNode;
            if (pred == null) {
                first = newNode;
            } else {
                pred.next = newNode;
            }
            size++;
        }
    }

    public boolean remove(Object o) {
        if (o == null) {
            for (Node<T> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    // 删除该结点
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<T> x = first; x != null; x = x.next) {
                if (x.item.equals(o)) {
                    // 删除该结点
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

    public T remove(int index) {
        // 范围检查
        checkPositionIndex(index);
        return unlink(node(index));
    }

    public T get(int index) {
        // 范围检查
        checkPositionIndex(index);
        return node(index).item;
    }

    public T set(int index, T element) {
        // 范围检查
        checkPositionIndex(index);
        Node<T> x = node(index);
        T oldVal = x.item;
        x.item = element;
        return oldVal;
    }

    private T unlink(Node<T> x) {
        final T element = x.item;
        final Node<T> prev = x.prev;
        final Node<T> next = x.next;

        // 修改前一结点的指针
        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        // 修改后一结点的指针
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }
        x.item = null;
        size--;
        return element;
    }


    private Node<T> node(int index) {
        // 前一半
        if (index < (size >> 1)) {
            Node<T> x = first;
            for (int i = 0; i < index; i++) {
                x = x.next;
            }
            return x;
        } else {
            Node<T> x = last;
            for (int i = size - 1; i > index; i--) {
                x = x.prev;
            }
            return x;
        }
    }

    private boolean checkPositionIndex(int index) {
        if (index < 0 || index > size) {
            throw new RuntimeException("下标越界!");
        }
        return true;
    }
}

全部评论

相关推荐

醉蟀:你是我今年见过的最美牛客女孩
点赞 评论 收藏
分享
小厂面经,也是我的处女面(30min)1.自我介绍2.spring&nbsp;boot的自动装配原理(好多类和接口的单词都忘了全称是啥了,就说了记得的单词,流程应该说对了吧)3.有用过redis吗?主要是用在实现什么功能(说了技术派用redis的zset来实现排行榜)5.有了解过Redisson吗?讲一下对于分布式锁的了解以及在什么场景下应用(说了秒杀场景)6.对mysql有了解吗?包括它的索引优化和创建(把想起来的全说了)7.了解设计模式吗?比如单例模式,为什么要使用单例模式,它的优点是什么(昨天刚看的设计模式)8.工厂模式有了解吗?主要的使用场景是?(也是昨天刚看的)9.场景题:有7个服务器,需要在早上十点定时的向数据库中的用户表中的用户发短信,如果做到发送的消息不重复,且如果发送失败了需要知道是到哪个用户失败了,这样下次就直接从这个用户开始(我答了用spring&nbsp;task来实现定时,用分布式锁来保证只有一份服务器可以发送消息,用消息队列来存储消息,然后用消息确认机制来保证错误信息的记录,以及在数据库或者业务层面完成消息消费的幂等性)10.场景题:如果在系统启动的时间就将数据库的所有用户相关的信息都读到一个hashmap中(这个没啥思路,没答好)27届的投了一个星期终于有一个面试了,大部分公司都只招26的
inari233:已oc,拒了
查看9道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务