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.
		
		
		
		
		
			
		
			
				
					
					
						
							206 lines
						
					
					
						
							4.6 KiB
						
					
					
				
			
		
		
	
	
							206 lines
						
					
					
						
							4.6 KiB
						
					
					
				| ---
 | |
| 链表
 | |
| ---
 | |
| 
 | |
| #### 目录
 | |
| 
 | |
| 1. 链表分类
 | |
|    - 单链表
 | |
|    - 循环链表
 | |
|    - 双向链表
 | |
|    - 双向循环链表
 | |
| 2. 常见链表算法题
 | |
|    - 单链表反转
 | |
|    - 链表中环的检测
 | |
|    - 两个有序链表的合并
 | |
|    - 删除链表倒数第 n 个结点
 | |
|    - 求链表的中间结点
 | |
| 3. 总结
 | |
| 
 | |
| #### 链表分类
 | |
| 
 | |
| ##### 单链表
 | |
| 
 | |
| 
 | |
| 
 | |
| ##### 循环链表
 | |
| 
 | |
| 
 | |
| 
 | |
| ##### 双向链表
 | |
| 
 | |
| 
 | |
| 
 | |
| ##### 双向循环链表
 | |
| 
 | |
| 
 | |
| 
 | |
| #### 常见链表算法题
 | |
| 
 | |
| 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<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. 两个有序链表的合并
 | |
| 
 | |
|    ```java
 | |
|    
 | |
|    ```
 | |
| 
 | |
| 4. 删除链表倒数第 n 个结点
 | |
| 
 | |
|    ```java
 | |
|    
 | |
|    ```
 | |
| 
 | |
| 5. 求链表的中间结点
 | |
| 
 | |
|    ```java
 | |
|    
 | |
|    ```
 | |
| 
 | |
|    
 | |
| 
 | |
| #### 总结
 | |
| 
 | |
| 面试中手写算法题最多的就是链表相关的,链表算法到底难不难?难?难得话一个题再写十遍还难不难?(气急败坏中...
 | |
| 
 | |
| 不过,链表中需要注意几个边界条件:
 | |
| 
 | |
| 1. 如果链表为空
 | |
| 2. 如果链表只有一个结点时
 | |
| 3. 如果链表只有两个结点时
 | |
| 4. 代码逻辑在处理头结点和尾结点时 |