【数据结构】链表

一、何为链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

三、手写LinkedList

参考JDK中的LinkedList,写法基本一致,仅用于自己学习。

java 复制代码
public class LinkedList<E> implements List<E> {

    transient int size = 0;

    transient Node<E> first;

    transient Node<E> last;

    @Override
    public boolean add(E e) {
        linkLast(e); // 默认尾插
        return false;
    }

    /**
     * 头插法
     * @param e
     */
    private void linkFirst(E e) {
        Node<E> f = first;
        Node<E> newNode = new Node<>(e, null, f);
        first = newNode;
        if (f == null) {
            last = newNode;
        } else {
            f.prev = newNode;
        }
        size++;
    }

    /**
     * 尾插法
     * @param e
     */
    private void linkLast(E e) {
        Node<E> l = last;
        Node<E> newNode = new Node<>(e, l, null);
        last = newNode;
        if (l == null) {
            first = newNode;
        } else {
            l.next = newNode;
        }
        size++;
    }

    /**
     * 插链操作
     * @param e
     */
    private void unLink(Node<E> e) {
        Node<E> prev = e.prev;
        Node<E> next = e.next;
        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            e.prev = null;
        }
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            e.next = null;
        }
        e.item = null;
        size--;
    }

    @Override
    public boolean addFirst(E e) {
        linkFirst(e);
        return true;
    }

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

    @Override
    public void remove(int index) {
        checkElementIndex(index);
        unLink(node(index));
    }

    private E unLinkFirst(Node<E> f) {
        E item = f.item;
        Node<E> next = f.next;
        f.item = null;
        f.next = null;
        first = next;
        if (next == null) {
            last = null;
        } else {
            next.prev = null;
        }
        size--;
        return item;
    }

    private E unLinkLast(Node<E> l) {
        E item = l.item;
        Node<E> prev = l.prev;
        l.item = null;
        l.prev = null;
        last = prev;
        if (prev == null) {
            first = null;
        } else {
            prev.next = null;
        }
        size--;
        return item;
    }

    @Override
    public E remove() { // 默认头删
        return removeFirst();
    }

    @Override
    public E removeFirst() {
        Node<E> f = first;
        if (f == null) {
            return null;
        }
        return unLinkFirst(f);
    }

    private Node<E> node(int index) {
        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 checkElementIndex(int index) {
        if (!isElementIndex(index)) {
            throw new RuntimeException(outOfBoundsMsg(index));
        }
    }

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

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

    @Override
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    
    private static class Node<E> {
        E item;
        Node<E> prev;
        Node<E> next;
        public Node(E item, Node<E> prev, Node<E> next) {
            this.item = item;
            this.prev = prev;
            this.next = next;
        }
    }
}

四、常见问题

  • JDK中LinkedList是双向链表,add方法默认是尾插法,remove方法默认是头删,是实现LRU算法的雏形
  • 相比于ArrayList,LinkedList更适用于在首尾部进行插入删除和查询操作。ArrayList的耗时操作主要体现在对元素的拷贝和位移,而LinkedList的耗时操作主要体现在遍历定位和创建节点,因此在不同数据规模下耗时不同,不能简单的认为LinkedList一定比ArrayList插入快。
相关推荐
X同学的开始1 小时前
数据结构之二叉树遍历
数据结构
AIAdvocate4 小时前
Pandas_数据结构详解
数据结构·python·pandas
jiao000015 小时前
数据结构——队列
c语言·数据结构·算法
kaneki_lh5 小时前
数据结构 - 栈
数据结构
铁匠匠匠5 小时前
从零开始学数据结构系列之第六章《排序简介》
c语言·数据结构·经验分享·笔记·学习·开源·课程设计
C-SDN花园GGbond5 小时前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法
CV工程师小林6 小时前
【算法】BFS 系列之边权为 1 的最短路问题
数据结构·c++·算法·leetcode·宽度优先
Navigator_Z7 小时前
数据结构C //线性表(链表)ADT结构及相关函数
c语言·数据结构·算法·链表
还听珊瑚海吗7 小时前
数据结构—栈和队列
数据结构
Aic山鱼7 小时前
【如何高效学习数据结构:构建编程的坚实基石】
数据结构·学习·算法