JDK1.8集合框架源码分析二-------------LinkedList

0.LinkedList特点

   0.1) 删除或新增效率高:不会移动数据元素,只会维护内部节点的关系

   0.2) 查询慢: 在其内部没有下标,也即没有索引,需要使用for循环遍历,LInkedList为了提高效率,采用折半查找算法

1.LinkedList的成员属性

   1.1  int size --- LinkedList容器现有的节点个数

   1.2 Node<E> first;--- 首节点,目的是为了查询方便,从里可以发起查询 

   1.3 Node<E> last--- 尾节点,目的: (1) 从这里添加元素 (2)也可以从这里发起查询

2.LinkedList的Node类的数据结构

    private static class Node<E>{
        E data;//节点数据
        Node<E> prev;//上一个节点
        Node<E> next;//下一个节点

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

3.LinkedList的数据结构

4.LinkedList添加元素

    private void linkLast(E e) {
        //创建一个临时变量存储容器的尾节点
        final Node<E> l = last;
        //创建一个以当前容器尾节点为上一个节点,null为下一个节点的新节点
        final Node<E> newNode = new Node<E>(e, l, null);
        //把新节点赋值给尾节点
        last = newNode;
        //如果首节点为空
        if(first == null){
            first = newNode;
        }else{
            l.next = newNode;
        }
        size ++ ;
    }

    @Override
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

5.LinkedList 指定下标index查询元素

    5.1) 数组越界检查   index >=0 && index < size

    5.2) 根据当前容器所存储的数据大小进行折半查找

          index < size >> 1 ====> index < size/2 从容器的首节点开始查询

          否则 从容器的尾节点开始查询                                                                                                                                               

                                 

    @Override
    public E get(int index) {
        checkElementIndex(index);
        return node(index).data;
    }

    private void checkElementIndex(int index) {
        if (index >= 0 && index < size) {
            return;
        }
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private Node<E> node(int index) {
        //即要想找到下标为index的节点,则只需要找到其相邻节点即可得到该节点的数据
        Node<E> node = null;
        if(index < size >> 1){
            node = first;
            for (int i = 0; i < index; i ++){
                node = node.next;
            }
        }else{
            node = last;
            for (int i = (size -1); i > index; i --){
                node = node.prev;
            }
        }
        return node;
    }

 6.LinkedList在指定下标index位置添加元素

             6.1) 数组下标越界检查   index>=0 && index<=size

             6.2) 找到下标所在的节点indexNode (index >=0 && index < size 只能找到这个范围的节点) 

             6.3) 下标所在的节点为新节点newNode的下一个节点--->newNode.next = indexNode

             6.4) 下标所在的节点的上一个节点indexOldPrevNode为新节点的上一个节点--->newNode.prev = indexOldPrevNode

             6.4.1) 如果indexNode节点的上一个节点为null,则indexNode当前为first节点,此时需要更新首节点的内容

             6.5)下标所在的节点的上一个节点的新值为新节点--->indexNode.prev = newNode

             6.6 ) 当index = size时 ,直接在容器的末尾添加节点即可


    private void linkBefore(E e, Node<E> indexNode) {
        //下标所在的节点的上一个节点
        Node<E> prev = indexNode.prev;
        //利用构造函数创建新节点,
        //新节点的上一个节点为下标所在节点的上一个节点
        //新节点的下一个节点为下标所在的节点
        Node<E> newNode = new Node<>(e,prev,indexNode);
        //下标所在节点的新的上一个节点为新节点
        indexNode.prev = newNode;
        //如果下标所在节点的老的上一个节点为null
        //则说明下标所在节点在插入新的节点之前为首节点
        //现在插入新节点之后,新节点则称为首节点
        if(prev == null){
            first = newNode;
        }else{
            //如果下标所在节点的老的上一个节点不为null
            //则说明下标所在的节点在插入新的节点之前不是首节点
            //则下标所在的节点的老的上一个节点的下一个节点为新节点
            prev.next = newNode;
        }
        size++;
    }

    @Override
    public boolean add(int index, E e) {
        checkElementIndexInPos(index);

        if (index == size){
            linkLast(e);
        }else{
            linkBefore(e,node(index));
        }
        return true;
    }

7.LinkedList指定下标删除节点

            7.1) 数组越界检查  index >=0 && index < size

            7.2) 找出下标所在的节点 indexNode

            7.3) indexNode.prev = oldIndexPrevNode; indexNode.next = oldIndexNextNode;

            7.4) 如果 oldIndexPrevNode = null,则 first = indexNode ,即删除的为首节点 此时 需要 first = oldIndexNextNode;

            7.5) 如果 oldIndexPrevNode != null 则 oldIndexPrevNode.next = oldIndexNextNode; 

            7.6) 如果 oldIndexNextNode = null,则 last = indexNode,即删除的是尾节点,需要last = oldIndexPrevNode;

            7.7) 如果 oldIndexNextNode != null, 则oldIndexNextNode.prev = oldIndexPrevNode;

    private E unlink(Node<E> indexNode) {
        final E data = indexNode.data;
        final Node<E> oldIndexPrevNode = indexNode.prev;
        final Node<E> oldIndexNextNode = indexNode.next;

        if(oldIndexPrevNode == null){
            first = oldIndexNextNode;
        }else{
            oldIndexPrevNode.next = oldIndexNextNode;
            indexNode.prev = null;//GC回收
        }

        if(oldIndexNextNode == null){
            last = oldIndexPrevNode;
        }else{
            oldIndexNextNode.prev = oldIndexPrevNode;
            indexNode.next = null;//GC回收
        }
        indexNode.data = null;//GC回收
        size--;
        return data;
    }

    @Override
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

 8.LIinkedList指定元素值删除

         8.1)  找出指定元素所对应的节点

         8.2)  根据节点删除数据和步骤7一样

    @Override
    public boolean remove(Object obj) {
        if(obj == null){
            //从首节点开始遍历,找到复合条件的节点
            for(Node<E> x = first; x.next !=null; x = x.next){
                if(x.data == null){
                    unlink(x);
                    return true;
                }
            }
        }else{
            for(Node<E> x = first; x.next !=null; x = x.next){
                if(obj.equals(x.data)){
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

9.自己手写LinkedList源码代码以及Junit测试类

package com.roger.collection.impl;

import com.roger.collection.RogerList;

public class RogerLinkedList<E> implements RogerList<E> {

    //容器中数据的大小
    private int size;
    //容器中首节点
    private Node<E> first;
    //容器中尾节点
    private Node<E> last;

    private void linkLast(E e) {
        //创建一个临时变量存储容器的尾节点
        final Node<E> l = last;
        //创建一个以当前容器尾节点为上一个节点,null为下一个节点的新节点
        final Node<E> newNode = new Node<E>(e, l, null);
        //把新节点赋值给尾节点
        last = newNode;
        //如果首节点为空
        if (first == null) {
            first = newNode;
        } else {
            l.next = newNode;
        }
        size++;
    }

    @Override
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    private void linkBefore(E e, Node<E> indexNode) {
        //下标所在的节点的上一个节点
        Node<E> prev = indexNode.prev;
        //利用构造函数创建新节点,
        //新节点的上一个节点为下标所在节点的上一个节点
        //新节点的下一个节点为下标所在的节点
        Node<E> newNode = new Node<>(e,prev,indexNode);
        //下标所在节点的新的上一个节点为新节点
        indexNode.prev = newNode;
        //如果下标所在节点的老的上一个节点为null
        //则说明下标所在节点在插入新的节点之前为首节点
        //现在插入新节点之后,新节点则称为首节点
        if(prev == null){
            first = newNode;
        }else{
            //如果下标所在节点的老的上一个节点不为null
            //则说明下标所在的节点在插入新的节点之前不是首节点
            //则下标所在的节点的老的上一个节点的下一个节点为新节点
            prev.next = newNode;
        }
        size++;
    }

    @Override
    public boolean add(int index, E e) {
        checkElementIndexInPos(index);

        if (index == size){
            linkLast(e);
        }else{
            linkBefore(e,node(index));
        }
        return true;
    }

    private void checkElementIndexInPos(int index) {
        if (index >= 0 && index <= size) {
            return;
        }
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    @Override
    public E get(int index) {
        checkElementIndex(index);
        return node(index).data;
    }

    private void checkElementIndex(int index) {
        if (index >= 0 && index < size) {
            return;
        }
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private Node<E> node(int index) {
        //即要想找到下标为index的节点,则只需要找到其相邻节点即可得到该节点的数据
        Node<E> node = null;
        if(index < size >> 1){
            node = first;
            for (int i = 0; i < index; i ++){
                node = node.next;
            }
        }else{
            node = last;
            for (int i = (size -1); i > index; i --){
                node = node.prev;
            }
        }
        return node;
    }

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

    private E unlink(Node<E> indexNode) {
        final E data = indexNode.data;
        final Node<E> oldIndexPrevNode = indexNode.prev;
        final Node<E> oldIndexNextNode = indexNode.next;

        if(oldIndexPrevNode == null){
            first = oldIndexNextNode;
        }else{
            oldIndexPrevNode.next = oldIndexNextNode;
            indexNode.prev = null;//GC回收
        }

        if(oldIndexNextNode == null){
            last = oldIndexPrevNode;
        }else{
            oldIndexNextNode.prev = oldIndexPrevNode;
            indexNode.next = null;//GC回收
        }
        indexNode.data = null;//GC回收
        size--;
        return data;
    }

    @Override
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }


    @Override
    public boolean remove(Object obj) {
        if(obj == null){
            //从首节点开始遍历,找到复合条件的节点
            for(Node<E> x = first; x.next !=null; x = x.next){
                if(x.data == null){
                    unlink(x);
                    return true;
                }
            }
        }else{
            for(Node<E> x = first; x.next !=null; x = x.next){
                if(obj.equals(x.data)){
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }


    private static class Node<E> {
        E data;//节点数据
        Node<E> prev;//上一个节点
        Node<E> next;//下一个节点

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

    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + size;
    }
}
package com.roger.collection;

public interface RogerList<E> {

    boolean add(E e);

    boolean add(int index, E e);

    E get(int index);

    int size();

    E remove(int index);

    boolean remove(Object obj);
}
package com.roger.collection.impl;

import com.roger.collection.RogerList;
import org.junit.Test;

public class RogerLinkerListTest {

    @Test
    public void testAdd() {

        RogerList<String> rogerArrayList = new RogerLinkedList<>();
        rogerArrayList.add("Roger");
        rogerArrayList.add("Mary");
        rogerArrayList.add("Bruce");
        for (int i = 0; i < rogerArrayList.size(); i++) {
            System.out.println(rogerArrayList.get(i));
        }

    }

    @Test
    public void testAddByPos() {
        RogerList<String> rogerArrayList = new RogerArrayList<String>(1);
        rogerArrayList.add("Roger");
        rogerArrayList.add("Mary");
        rogerArrayList.add("Bruce");
        rogerArrayList.add(0, "Andy");
        for (int i = 0; i < rogerArrayList.size(); i++) {
            System.out.println(rogerArrayList.get(i));
        }
    }

    @Test
    public void testRemove(){
        RogerList<String> rogerArrayList = new RogerArrayList<String>(1);
        rogerArrayList.add("Roger");
        rogerArrayList.add("Mary");
        rogerArrayList.add("Bruce");
        rogerArrayList.add(3, "Andy");


        rogerArrayList.remove(3);
        rogerArrayList.add("Bruce1");
        for (int i = 0; i < rogerArrayList.size(); i++) {
            System.out.println(rogerArrayList.get(i));
        }
    }

    @Test
    public void testRemoveByObj(){
        RogerList<String> rogerArrayList = new RogerArrayList<String>(1);
        rogerArrayList.add("Roger");
        rogerArrayList.add("Mary");
        rogerArrayList.add(null);
        rogerArrayList.add("Bruce");
        rogerArrayList.add(3, "Andy");
        rogerArrayList.add(null);

        rogerArrayList.remove("Andy");
        rogerArrayList.remove(null);
        for (int i = 0; i < rogerArrayList.size(); i++) {
            System.out.println(rogerArrayList.get(i));
        }
    }
}

猜你喜欢

转载自blog.csdn.net/lihongtai/article/details/84983544