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
6 years ago
|
---
|
||
|
链表
|
||
|
---
|
||
|
|
||
|
#### 目录
|
||
|
|
||
|
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<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. 代码逻辑在处理头结点和尾结点时
|