You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

4.6 KiB

链表

目录

  1. 链表分类
    • 单链表
    • 循环链表
    • 双向链表
    • 双向循环链表
  2. 常见链表算法题
    • 单链表反转
    • 链表中环的检测
    • 两个有序链表的合并
    • 删除链表倒数第 n 个结点
    • 求链表的中间结点
  3. 总结

链表分类

单链表

循环链表

双向链表

双向循环链表

常见链表算法题

  1. 单链表的反转

    public class LinkedListDemo {
    
        private static Node head;
    
        public static void main(String[] args) {
            head = new Node(0);
            head.next = new Node(1);
            head.next.next = new Node(2);
            head.next.next.next = new Node(3);
    
            reverseLinkedList();
    
            while (head != null) {
                System.out.println(head.value);
                head = head.next;
            }
        }
    
        //单链表的反转
        private static void reverseLinkedList() {
            if (head == null || head.next == null) {
                return;
            }
            Node p1 = head;
            Node p2 = head.next;
            Node p3 = null;
            while (p2 != null) {
                p3 = p2.next;
                p2.next = p1;
                p1 = p2;
                p2 = p3;
            }
            head.next = null;
            head = p1;
        }
    
        static class Node {
            int value;
            Node next;
    
            Node(int value) {
                this.value = value;
            }
        }
    }
    

    参考:漫画:如何将一个链表“逆序”?

  2. 链表中环的检测

    这道题有三种解法:

    public class LinkedListDemo {
    
        private static Node head;
    
        public static void main(String[] args) {
            head = new Node(0);
            head.next = new Node(1);
            head.next.next = new Node(2);
            head.next.next.next = new Node(3);
            head.next.next.next.next = head.next;
    
            boolean isHasCycleBySet = hasCycleBySet();
            System.out.println(isHasCycleBySet);
            boolean isHasCycleByRun = hasCycleByRun();
            System.out.println(isHasCycleByRun);
            boolean isHasCycleByMagic = hasCycleByMagic();
            System.out.println(isHasCycleByMagic);
        }
    
        //用 HashSet 判断
        private static boolean hasCycleBySet() {
            if (head == null || head.next == null) {
                return false;
            }
            Set<Node> set = new HashSet<>();
            while (head != null) {
                if (set.contains(head)) {
                    return true;
                } else {
                    set.add(head);
                }
                head = head.next;
            }
            return false;
        }
    
        //快慢指针
        private static boolean hasCycleByRun() {
            if (head == null || head.next == null) {
                return false;
            }
            Node p1 = head;
            Node p2 = head.next;
            while (p1 != p2) {
                if (p2 == null || p2.next == null) {
                    return false;
                }
                p1 = p1.next;
                p2 = p2.next.next;
            }
            return true;
        }
    
        //魔法数解法
        private static boolean hasCycleByMagic() {
            if (head == null || head.next == null) {
                return false;
            }
            while (head != null) {
                if (head.value == 2 << 30) {
                    return true;
                } else {
                    head.value = 2 << 30;
                }
                head = head.next;
            }
            return false;
        }
    
        static class Node {
            int value;
            Node next;
    
            Node(int value) {
                this.value = value;
            }
        }
    }
    
  3. 两个有序链表的合并

    
    
  4. 删除链表倒数第 n 个结点

    
    
  5. 求链表的中间结点

    
    

总结

面试中手写算法题最多的就是链表相关的,链表算法到底难不难?难?难得话一个题再写十遍还难不难?(气急败坏中...

不过,链表中需要注意几个边界条件:

  1. 如果链表为空
  2. 如果链表只有一个结点时
  3. 如果链表只有两个结点时
  4. 代码逻辑在处理头结点和尾结点时