zoukankan      html  css  js  c++  java
  • LinkedList 底层实现原理

    LinkedList的底层实现原理

    LinkedList 底层数据结构为双向链表,链表结构,基于一个个链表节点Node

    1,Inner Class 内部类

    private static class Node<E>{
        E item;//当前节点下的当前元素
        Node<E> next;//下一个节点
        Node<E> prev;//上一个节点

        //constructor
        Node(Node<E>prev , E element , Node<E> next){
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

    2,属性 fields
    transient size = 0;
    transient Node<E> first;
    transient Node<E> last;

    //LinkedList 底层是链表结构,所以其属性就是封装了链表中一个有多少个节点,以及第一个节点,最后一个节点。


    3,构造方法 constructor
    //无参构造方法
    public LinkedList(){

    }
    //public LinkedList(Collection <? extends E> c){
       this();
       addAll(size,c);
    }


    public boolean addAll(int index,Collection <? extends E>c){
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        if(numNew == 0)
            return false;
      
        Node<E> pred,succ;//pred 代表要有变化的前节点, succ 代表要变化的后节点
        例:{“good”,"bad","bye","see","to","two","you","me"} 要实现在index = 2 处insert 一个集合,那么Node<E> prev 就是“bad”所在的节点,Node<E> succ 就是"bye" 所在的节点。

        if(index == size){
          succ = null;
          pred = last;
          //按着顺序插入的情况会相等,必须先插入长度为3的集合,然后顺着插入在index 为4 的位置继续插入
        }else{
          succ = node(index);//-[]-[]-[]-[]-[]/-[]-[]  /代表插入,succ 后节点就是/ 之后的节点
          pred = succ.prev;
        }
       //开始插入
        for(Object o:a){
            @SupressWarnings("unchecked") E e  = (E)o;
            Node<E> newNode = new Node<>(pred,e,null);
            if(pred == null)
                first = newNode;
            else
               pred.next = newNode;
           pred = newNode;//为了循环中下一次的赋值,得把pred赋值成当前元素
        }
      
        if(succ == null){
            last = pred;
        }else{
            pred.next = succ;
            succ.prev = pred;
            //因为pred 在for 循环中插入时候一直有更新,所以这段代码的作用是为了将插入的最后一个节点后变化后的节点连接起来,形成一个新的链表。
        }
    }

    //找到即将有变化的节点,这个节点永远是变化的后节点
    Node<E> node(int index){
        //二分法,如果变化在前半部分,则找出first 如果变化在后半部分,则找出last
        if(index < (size >> 1)){//前半部分
            Node<E> x = first;
            for(int i = 0; i < index; i++)
                x = x.next;
            return x;
        }else{
            Node<E> x = last;
            for(int i = size - 1; i>index; i--){
               x = x.prev;
            return x;
            }
        }
    }


    private void checkPositionIndex(int index){
        if(!isPositionIndex(index))
            throw new IndexOutOfBoundsException(OutOfBoundsMsg(index));
    }

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

    //addAll(int index,Collection<? extends E> c)这个方法可以用于LinkedList 的初始化中,
    可以加载指定集合到目标集合中。
    另外,这个方法也可以用于在目标集合指定位置插入指定集合。

    4,add
    public boolean add(E e){
        linkLast(e);
        return true;
    }

    void linkLast(E e){

        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l,e,null);
        last = newNode;
        if(l == null){
        first = newNode;
        }else{
        l.next = newNode;
        }
        size++;
        modCount++;
    }

    //add方法中范型E控制add元素的类型,如果类型不对,则编译报错,否则不会出现异常。
    在最后一个节点后面增加新元素,上一个节点是last,当前是e,下一个null,需要判断当前增加的是不是第一个元素,是则将新增元素赋值为链中的first,不是则将当前元素赋值为last的next元素。

    5 addFirst
    public void addFirst(E e){
        linkFirst(e);
    }

    private void linkFirst(E e){
        Final Node<E> f = first;
        Final Node<E> newNode = new Node(null,e,f);
        first = newNode;

        //每增加一个节点,都要创建和已知节点的关联
        if(f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
        modCount++;
    }


    6,addLast
    调用的也是linkLast(E e)方法,和add(E e) 是调用一样的方法,只不过add(E e) 返回类型是boolean 型,addLast是void.

    7,removeFirst

    public E removeFirst(E e){
        final Node<E> f = first;
        if(f == null)
            throw new NoSuchElementException();

        return unLinkFirst(f);
    }

    privte E unLinkFirst(Node<E> f){
        final E element = f.item;
        Node<E> next = f.next;
        //f 将删除,f的节点关系也需被删除
        f.item = null;
        f.next = null;
       
        first = next;
        if(next == null)
            last = next;
        else
            next.prev = null;

        size--;
        modCount++;

       return element;
    }

    8,removeLast

    public E removeLast(E e){
        final Node<E> l = last;
        if(last == null)
            throw new NoSuchElementException();
        return unLinkLast(l);
    }

    private E unLinkLast(Node<E> l){
        final E element = l.item;
        fianl Node<E> prev = l.prev;
        //clear relationship
        l.item = null;
        l.prev = null;
        //重新设定
        last = prev;

        if(prev == null)
            first = prev;
        else
            prev.next = null;

        size--;
        modeCount++:
        return element;
    }

    9,getFirst

    public E getFirst(){
        fianl Node<E> f = first;
        if(f == null)
            throw new NoSuchElementException();
        return f.item;
    }

    10,getLast

    public E getLast(){
        final Node<E> l = last;
        if(l == null)
            throw new NoSuchElementException();
        return l.item;
    }

     11,查询

    public E get(int index){
        CheckElementIndex(index);
        return node(index).item;//通过node方法获取到当前index 的节点
    }

  • 相关阅读:
    第二阶段团队冲刺第二天站立会议
    第二阶段冲刺第一天站立会议
    对身边常用的软件进行评价
    学习进度条
    进度条
    团队冲刺第四天站立会议
    用户模板及场景分析
    团队冲刺第一天战略会议
    团队冲刺第九天
    团队冲刺第八天
  • 原文地址:https://www.cnblogs.com/pickKnow/p/9199247.html
Copyright © 2011-2022 走看看