博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LinkedList 底层实现原理
阅读量:5051 次
发布时间:2019-06-12

本文共 4005 字,大约阅读时间需要 13 分钟。

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

你可能感兴趣的文章
微信支付choosewxpay:fail
查看>>
简单的 JSON 对象进行深拷贝最简单的方法
查看>>
Java method Exception throw with return instance.
查看>>
记事本其他功能实现(打印)
查看>>
2.Installation guide
查看>>
[原创]java WEB学习笔记21:MVC案例完整实践(part 2)---DAO层设计
查看>>
[原创]java WEB学习笔记33:Session 案例 之 购物车
查看>>
约瑟夫环问题的实现
查看>>
子元素scroll父元素容器不跟随滚动JS实现
查看>>
nodejs操作mongodb
查看>>
win10 uwp 获得缩略图
查看>>
[DP/变种背包] SOFTWARE
查看>>
OpenCV + python 实现人脸检测(基于照片和视频进行检测)
查看>>
ASP.NET同页面内【用户控件与父页面】以及【用户控件与用户控件】之间方法
查看>>
windows server 2012 如何开启 hyper-v 并创建虚拟机
查看>>
java-a实现压缩与解压缩(zip、gzip)
查看>>
Linux下MySql字符集修改办法
查看>>
MYSQL的数据类型以及建库策略
查看>>
洛谷P2341 [HAOI2006] 受欢迎的牛
查看>>
并发锁之二:ReentrantReadWriteLock读写锁
查看>>