--- 链表 --- #### 目录 1. 链表分类 - 单链表 - 循环链表 - 双向链表 - 双向循环链表 2. 常见链表算法题 - 单链表反转 - 链表中环的检测 - 两个有序链表的合并 - 删除链表倒数第 n 个结点 - 求链表的中间结点 3. 总结 #### 链表分类 ##### 单链表 ![](https://i.loli.net/2019/02/25/5c73a3d48b8f4.jpg) ##### 循环链表 ![](https://i.loli.net/2019/02/25/5c73a4202fc70.jpg) ##### 双向链表 ![](https://i.loli.net/2019/02/25/5c73a435a1dd8.jpg) ##### 双向循环链表 ![](https://i.loli.net/2019/02/25/5c73a44c30c40.jpg) #### 常见链表算法题 1. 单链表的反转 ```java 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; } } } ``` 参考:[漫画:如何将一个链表“逆序”?](https://mp.weixin.qq.com/s/MR_qAbonFqGF_ljeWUC26w) 2. 链表中环的检测 这道题有三种解法: ```java 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 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. 两个有序链表的合并 ```java ``` 4. 删除链表倒数第 n 个结点 ```java ``` 5. 求链表的中间结点 ```java ``` #### 总结 面试中手写算法题最多的就是链表相关的,链表算法到底难不难?难?难得话一个题再写十遍还难不难?(气急败坏中... 不过,链表中需要注意几个边界条件: 1. 如果链表为空 2. 如果链表只有一个结点时 3. 如果链表只有两个结点时 4. 代码逻辑在处理头结点和尾结点时