LinkedList源码解读

1.背景

这一节来带着大家一起阅读LinkedList的源码

2.先来认识一下什么是双向链表

示例图:

代码:

package com.ldp.collection.demo01;

import org.junit.Test;

/**
 * @author 姿势帝-博客园
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 04/05 6:03
 * @description
 */
public class Test04LinkedList {
    /**
     * 双向链表理解
     */
    @Test
    public void test01() {
        // 定义三个节点
        Node node1 = new Node("张无忌");
        Node node2 = new Node("赵敏");
        Node node3 = new Node("周芷若");
        // 将节点node1->node2->node3 依次使用双向链表链接
        // node1->node2
        node1.next = node2; // 节点1的下一个元素是节点2
        node2.prev = node1; // 节点2的上一个元素是节点1
        // node2->node3
        node2.next = node3; // 节点2的下一个元素是节点3
        node3.prev = node2; // 节点3的上一个元素是节点2

        Node first = node1;// 头节点为node1
        Node last = node3; // 尾节点为node3

        printNode(first, true); // 从头到尾
        printNode(last, false);    // 从尾到头遍历

        System.out.println("尾部添加一个元素:小昭");
        Node node4 = new Node("小昭");
        last.next = node4;
        node4.prev = last;
        last = node4;
        printNode(first, true);

        System.out.println("头部添加一个元素:张三丰");
        Node node5 = new Node("张三丰");
        node5.next = first;
        first.prev = node5;
        first = node5;
        printNode(first, true);

        // 在中间添加一个节点
        System.out.println("在node1[张无忌]与node2[赵敏]之前添加一个:node6[金毛狮王]");
        Node node6 = new Node("金毛狮王");
        node1.next = node6; // 张无忌的下一个是金毛狮王
        node6.prev = node1; // 金毛狮王的上一个是张无忌

        node6.next = node2; // 金毛狮王的下一个是赵敏
        node2.prev = node6; // 赵敏的上一个是金毛狮王
        printNode(first, true);
    }

    /**
     * 节点遍历
     *
     * @param node 遍历的节点
     * @param flag flag=true表示从头到尾遍历,flag=false从尾到头遍历
     */
    public void printNode(Node node, boolean flag) {
        System.out.println("节点遍历开始......");
        while (true) {
            if (node == null) break;
            System.out.println("当前节点数据为:" + node.item);
            if (flag) {
                node = node.next; // 指向下一个节点,从头到尾遍历
            } else {
                node = node.prev; // 指向上一个节点,从尾到头遍历
            }
        }
        System.out.println("   ");
    }
}
class Node {
    Node prev; // 上一个节点
    Object item; //  数据
    Node next;// 下一个节点
    public Node(Object item) {
        this.item = item;
    }
}
View Code

3.源码解读

代码中重点解读了add方法,与remove方法,get方法

package com.ldp.collection.my;

import java.util.*;

/**
 * @author 姿势帝-博客园
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 04/05 6:51
 * @description
 */
public class MyLinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
    transient int size = 0;
    transient Node<E> first;
    transient Node<E> last;

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

    void linkLast(E e) {
        final Node<E> l = last;// 当前最后一个节点为 l
        final Node<E> newNode = new Node<>(l, e, null);// 新建立一个节点,上一为l,下一个为null
        last = newNode;// 设置最后一个节点为 新的节点
        if (l == null) // 最后一个节点为空(首次添加节点的时候),newNode是第一个节点也是最后一个节点
            first = newNode;
        else
            l.next = newNode;// 如果当前的最后一个节点不为空,那么它的下一个节点为newNode
        size++; // 节点数累加1
        modCount++; // 修改次数累加1
    }

    public E get(int index) {
        checkElementIndex(index); // 检查下标是否越界
        return node(index).item;// 根据下标取节点
    }

    /**
     * 检查下标是否越界
     */
    private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + size();
    }

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

    /**
     * 根据下标删除节点
     *
     * @param index
     * @return
     */
    public E remove(int index) {
        checkElementIndex(index);// 判断下标是否越界
        return unlink(node(index));
    }

    /**
     * 删除当前节点
     *
     * @param x
     * @return
     */
    E unlink(Node<E> x) {
        final E element = x.item;// x节点的元素值
        final Node<E> next = x.next; // x节点的下一个节点
        final Node<E> prev = x.prev; // x节点的上一个节点
        // 处理x节点的下一个节点的下一个节点
        if (prev == null) {// x节点的上一个节点为null,说明x节点就是第一个节点,删除x节点后,x的下一个节点为第一个节点
            first = next;
        } else {
            prev.next = next;
            x.prev = null;// 切断x的上一个节点
        }
        // 处理x节点的上一个节点的上一个节点
        if (next == null) {// x的下一个节点为null,说明x节点是最后一个节点,删除x节点后,x的上一个节点为最后一个节点
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;// 切断x的下一个节点
        }
        x.item = null; // x节点的数据设置为空
        size--;// 长度减一
        modCount++; // 修改次数加一
        return element; // 返回删除的元素
    }

    /**
     * 根据下标取出节点
     *
     * @param index
     * @return
     */
    Node<E> node(int index) {
        if (index < (size >> 1)) { // size >> 1 表示长度除以2,如果下标小于长度的1/2则从头开始遍历
            Node<E> x = first;
            for (int i = 0; i < index; i++)// 循环遍历一直取下一个,直到指定的下标
                x = x.next;// 下个表示从头遍历
            return x;
        } else { // 下标不小于长度的1/2则从尾开始遍历
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev; // 上一个表示从尾遍历
            return x;
        }
    }

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

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

    @Override
    public ListIterator<E> listIterator(int index) {
        return null;
    }

    @Override
    public void addFirst(E e) {

    }

    @Override
    public void addLast(E e) {

    }

    @Override
    public boolean offerFirst(E e) {
        return false;
    }

    @Override
    public boolean offerLast(E e) {
        return false;
    }

    @Override
    public E removeFirst() {
        return null;
    }

    @Override
    public E removeLast() {
        return null;
    }

    @Override
    public E pollFirst() {
        return null;
    }

    @Override
    public E pollLast() {
        return null;
    }

    @Override
    public E getFirst() {
        return null;
    }

    @Override
    public E getLast() {
        return null;
    }

    @Override
    public E peekFirst() {
        return null;
    }

    @Override
    public E peekLast() {
        return null;
    }

    @Override
    public boolean removeFirstOccurrence(Object o) {
        return false;
    }

    @Override
    public boolean removeLastOccurrence(Object o) {
        return false;
    }

    @Override
    public boolean offer(E e) {
        return false;
    }

    @Override
    public E remove() {
        return null;
    }

    @Override
    public E poll() {
        return null;
    }

    @Override
    public E element() {
        return null;
    }

    @Override
    public E peek() {
        return null;
    }

    @Override
    public void push(E e) {

    }

    @Override
    public E pop() {
        return null;
    }

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

    @Override
    public Iterator<E> descendingIterator() {
        return null;
    }
}
View Code

 

测试代码:

 @Test
    public void test02() {
        // LinkedList list = new LinkedList();
        MyLinkedList list = new MyLinkedList();
        list.add("张无忌");
        list.add("赵敏");
        list.add("张无忌");
        list.add("周芷若");
        System.out.println("size=" + list.size());
        System.out.println("获取index=3的元素"+list.get(3));//周芷若
        // System.out.println("list=" + list);// 因这个方法没有重写listIterator(int index),不能使用迭代器
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println("删除后index=3的元素");
        list.remove(3);
        System.out.println("删除后的list");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    } 

完美!

posted @ 2022-04-05 18:49  李东平|一线码农  阅读(41)  评论(0编辑  收藏  举报