单链表的实现(Java)

385 阅读3分钟

一、单链表介绍

链表是一种不需要连续内存空间的线性表。

而单链表是最简单的链表。可以将单链表想象成如下图所示:

每个内存块被称为结点。

每个结点有一个 数据域和指针域,数据域用来存储数据,而指针 域用来保存下一个结点的地址。

单链表的尾结点指向 NULL。

二、插入

只需要改变相邻结点的指针的指向,就可以实现单链表的插入,时间复杂度为 O(1)。

如图所示:

翻译成代码:

  /**
     * 将新的节点插入到指定节点后
     *
     * @param preNode 指定节点
     * @param newNode 新的节点
     */
    public void insert(Node<T> preNode, Node<T> newNode) {
        newNode.next = preNode.next;
        preNode.next = newNode;
        length++;
    }

三、删除

和插入类似,只需要相邻结点的指针指向,就可以完成单链表的删除操作。时间复杂度为 O(1)。

如图所示:

翻译成代码就是:

/**
     * 给定被删除元素的前一个结点,删除下一个结点
     *
     * @param preNode
     */
    public void del(Node preNode) {
        preNode.next = preNode.next.next;
        length--;
    }

四、查找

由于单链表不需要连续的内存空间,所以不需要搬运数据,插入和删除的时间复杂度很低,为 O(1)。

但是有利就有弊,由于内存空间不连续,所以想要找到第 k 个结点,就只能通过遍历的方式。时间复杂度为 O(n)。

  /**
     * 访问第 k 个结点, k 从 0 开始
     *
     * @param k
     * @return
     */
    public Node find(int k) {
        int cnt = 0;
        Node temp = head;
        // 找到第 k 个元素
        while (cnt != k) {
            temp = temp.next;
            cnt++;
        }
        return temp;
    }

五、总结

单链表是链表最简单的一种,和数组一样,链表属于线性表。

单链表的插入和删除操作非常方便,时间复杂度为 O(1)。

单链表随机访问第 k 个结点的时间复杂度为 O(n)。

六、完整代码

/**
 * 单链表的实现
 *
 * @author liyanan
 * @date 2020/1/2 13:16
 */
public class SingleLinkedList<T> {
    public static class Node<T> {
        /**
         * 存储数据
         */
        public T data;
        /**
         * 指向下一个节点
         */
        public Node next;

        public Node(T data) {
            this.data = data;
        }
    }

    /**
     * 单链表的头结点,该节点不存储有效数据,只是为了方便
     */
    private Node<T> head;

    /**
     * 单链表的长度
     */
    private int length;

    public SingleLinkedList() {
        head = null;
        length = 0;
    }

    /**
     * 插入节点到单链表尾部
     *
     * @param newNode
     */
    public void insertLast(Node<T> newNode) {
        if (length == 0) {
            head = newNode;
            length++;
        } else {
            Node<T> temp = head;
            // 找到链表尾结点
            while (temp.next != null) {
                temp = temp.next;
            }
            insert(temp, newNode);
        }
    }

    /**
     * 将新的节点插入到指定节点后
     *
     * @param preNode 指定节点
     * @param newNode 新的节点
     */
    public void insert(Node<T> preNode, Node<T> newNode) {
        newNode.next = preNode.next;
        preNode.next = newNode;
        length++;
    }

    public void insertFirst(Node<T> newNode) {
        if (length == 0) {
            head = newNode;
        } else {
            newNode.next = head;
            head = newNode;
        }
        length++;
    }

    /**
     * 删除数据域为指定值的元素
     *
     * @param e
     */
    public void del(T e) {
        Node temp = head;
        while (temp != null) {
            if (temp.next.data.equals(e)) {
                del(temp);
                return;
            }
            temp = temp.next;
        }
    }

    /**
     * 给定被删除元素的前一个结点,删除下一个结点
     *
     * @param preNode
     */
    public void del(Node preNode) {
        preNode.next = preNode.next.next;
        length--;
    }

    /**
     * 访问第 k 个结点, k 从 0 开始
     *
     * @param k
     * @return
     */
    public Node find(int k) {
        int cnt = 0;
        Node temp = head;
        // 找到第 k 个元素
        while (cnt != k) {
            temp = temp.next;
            cnt++;
        }
        return temp;
    }

    /**
     * 打印单链表所有有效结点
     *
     * @return
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        Node temp = head;
        while (temp != null) {
            sb.append(temp.data);
            sb.append(" -> ");
            temp = temp.next;
        }
        sb.append("null, length = ");
        sb.append(length);
        return sb.toString();
    }

    public static void main(String[] args) {
        SingleLinkedList<Integer> single = new SingleLinkedList<>();
        Node<Integer> node1 = new Node<>(1);
        Node<Integer> node2 = new Node<>(2);
        Node<Integer> node3 = new Node<>(3);
        Node<Integer> node4 = new Node<>(4);
        Node<Integer> node5 = new Node<>(5);
        single.insertLast(node1);
        single.insertLast(node2);
        single.insertLast(node3);
        single.insertLast(node4);
        single.insertLast(node5);
        System.out.println(single);
        single.insert(node1, new Node<>(10));
        System.out.println(single);
        single.del(node3);
        System.out.println(single);
        single.del(5);
        System.out.println(single);

        Node node = single.find(0);
        System.out.println(node.data);
    }
}