3.链表-java

链表与数组的区别

https://www.processon.com/diagraming/606c14aa7d9c0829db70c8a0

单链表与循环链表

注意链表中的头结点和尾结点。

循环链表从尾可以方便的到头,适合环型结构数据,比如约瑟夫问题。

双向链表

优势:

O(1) 时间复杂度找到前驱结点

删除,插入更高效。考虑以下两种情况:

  • 删除结点中“值等于某个给定值”的结点
  • 删除给定指针指向的结点

查询更高效:记录上次查找的位置 p,每次查询时,根据要查找的值与 p 的大小关系,决定是往前还是往后查找,所以平均只需要查找一半的数据。

再次比较数组和链表

从复杂度分析:

时间复杂度 数组 链表
插入删除 O(n) O(1)
随机访问 O(1) O(n)

其它角度:

  • 内存连续,利用 CPU 的缓存机制,预读数组中的数据,所以访问效率更高。

  • 而链表在内存中并不是连续存储,所以对 CPU 缓存不友好,没办法有效预读。

  • 数组的大小固定,即使动态申请,也需要拷贝数据,费时费力。

  • 链表支持动态扩容.

public class SinglyLinkedList {
    Node head;

    public void insertTail(int value) {
        if (head == null) {
            insertToHead(value);
            return;
        }
        Node q = head;
        while (q.next != null) {
            q = q.next;
        }
        Node newNode = new Node(value);
        q.next = newNode;

    }

    public void insertToHead(int value) {
        Node newNode = new Node(value);
        newNode.next = head;
        head = newNode;

    }

    public boolean deleteByValue(int value) {
        if (head == null)
            return false;

        Node p = head;
        Node q = null;
        while (p != null && p.data != value) {
            q = p;
            p = p.next;
        }
        // 链表中,没有 value
        if (p == null)
            return false;
        // 数据在 head 上
        if (q == null) {
            head = head.next;
        } else {
            q.next = p.next;
        }
        return true;

    }

    public Node findByValue(int value) {
        if (head == null)
            return null;
        Node q = head;
        while (q != null && q.data != value) {
            q = q.next;
        }
        if (q == null)
            return null;

        return q;
    }

    public void insertAfter(Node node, int value) {
        if (node == null)
            return;

        Node newNode = new Node(value);
        newNode.next = node.next;
        node.next = newNode;

    }

    public void insertBefore(Node node, int value) {
        if (node == null)
            return;
        if (head == null) {
            insertToHead(value);
        } else {
            Node q = head;
            while (q != null && q.next != node) {
                q = q.next;
            }
            if (q == null)
                return;
            Node newNode = new Node(value);
            newNode.next = q.next;
            q.next = newNode;
        }

    }

    public void printAll() {
        if (head == null)
            return;
        Node q = head;
        while (q != null) {
            System.out.print(q.data + "  ");
            q = q.next;
        }
        System.out.println();
    }

    public static class Node {
        int data;
        Node next;

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

    public static void main(String[] args) {
        SinglyLinkedList link = new SinglyLinkedList();
        int data[] = { 1, 2, 5, 3, 1 };
        for (int i = 0; i < data.length; i++) {
            link.insertTail(data[i]);
        }
        link.insertToHead(99);
        // 打印内容为 99 1 2 5 3 1
        link.printAll();
        link.deleteByValue(2);
        System.out.println(!link.deleteByValue(999));
        System.out.println(link.deleteByValue(99));
        // 打印内容为 1 5 3 1
        link.printAll();
        System.out.println(link.findByValue(2) == null);
        Node newNode = link.findByValue(3);
        link.insertAfter(newNode, 10);
        System.out.println(link.findByValue(3).next.data == 10);
        link.insertBefore(newNode, 30);
        System.out.println(link.findByValue(5).next.data == 30);

    }

}