目录在这里哦~
0 勇士救主的故事
公主被巨龙 昆图库塔卡提考特苏瓦西拉松
抓走了,勇士 达拉崩吧斑得贝迪卜多比鲁翁
出发去救公主
勇士 达拉崩吧斑得贝迪卜多比鲁翁
到了 拉西卡帕斯蒂谷鹏大草原
,发现了去往 西路伽什材科安丰黑森林
的道路;
勇士 达拉崩吧斑得贝迪卜多比鲁翁
到了 西路伽什材科安丰黑森林
,发现了去往 哲石亦作步纸明子风雪山
的秘密;
勇士 达拉崩吧斑得贝迪卜多比鲁翁
到了 哲石亦作步纸明子风雪山
,发现了去往 巨龙山洞
的秘密;
最后勇士 达拉崩吧斑得贝迪卜多比鲁翁
打败了巨龙 昆图库塔卡提考特苏瓦西拉松
,就出了公主 公主米娅莫拉苏娜丹妮谢莉红
结束,这就是勇士救公主的故事
附上地图:
简单来说呢,就是从 A
找到了去 B
的路,从 B
找到了去 C
的路,从 C
找到了去D的路
1 链表的介绍
链表是一种 线性表
,链表中的数据存储在一个个的 节点
里,节点
不一定是连续存储的,在每一个 节点
中,除了存储数据以外,还会存储下一个 节点
的 位置信息(内存地址)
,根据此 位置信息(链接)
可以找到下一个 节点
。
2 链表的特点
2.1 优点
数据的插入和删除都相当方便,有新数据插入就向系统申请一块内存空间,而数据被删除后,就可以把这块内存空间还给系统,加入和删除都不需要移动大量的数据。
2.2 缺点
设计数据结构时比较麻烦,并且在查找数据时,也无法像静态数据(如数组)那样可以随机读取数据,必须要按序查找到该数据为止。
2.3 复杂度
3 单链表的增操作和删操作
3.1 单链表节点的数据结构
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
3.2 增
在 node
节点后插入 target
节点分两步:
第一步,把 target
的 next
指针指向 node
的 next
节点上
target.next = node.next
第二步,把 node
的 next
指针指向 target
指针
node.next = target
3.3 删
要删除 node
候面的 target
节点,只需要一步,把 node
的 next
指针指向 target
的 next
指针指向的节点上即可
node.next = target.next
4 双链表的增操作和删操作
4.1 双链表节点的数据结构
class ListNode {
int val;
ListNode next;
ListNode pre;
ListNode(int x) {
val = x;
next = null;
pre = null;
}
}
4.2 增
在双链表 node
后边插入一个 target
节点,需要执行四步操作:
第一步,把 target
的 next
指针指向 node
的 next
指针指向的对象
target.next = node.next
第二步,把node
的next
指向的对象的pre
指针指向 target
node.next.pre = target
第三步,把 target
的 pre
指针指向 node
节点
target.pre = node
第四步,把 node
的 next
指针指向 target
节点
node.next = target
4.3 删
在双链表中删除 target
节点分两步:
第一步,把 target
节点的 next
指针指向的节点的 pre
指针指向 node
target.next.pre = node
第二步,把 node
的 next
指针指向 target
的 next
指针指向的节点
node.next = target.next
5 实现链表
5.1 链表的几个方法
int get(int index)
获取指定 index 的元素
void addAtHead(int val)
添加元素到链表头部
void addAtTail(int val)
添加元素到链表尾部
void addAtIndex(int index, int val)
添加元素到链表指定 index 处
void deleteAtIndex(int index)
删除链表指定 index 的元素
5.2 code
设计链表的实现。链表中的节点应该具有两个属性:val
和 next
。val
是当前节点的值,next
是指向下一个节点的指针引用。
class MyLinkedList {
private ListNode Head;
int size;
public MyLinkedList() {
Head = new ListNode(0); // 初始化头节点
size = 0; // 初始化链表大小
}
// 获取指定 index 的元素
public int get(int index) {
if (index < 0 || index >= size) return -1; // 如果 index 在索引之外,直接返回 -1
ListNode curr = Head.next;
for (int i = 0; i < index; i++) curr = curr.next; // 遍历找到我们需要的位置
return curr.val;
}
// 添加元素到链表头部
public void addAtHead(int val) {
addAtIndex(0, val);
}
// 添加元素到链表尾部
public void addAtTail(int val) {
addAtIndex(size, val);
}
// 添加元素到链表指定 index 处
public void addAtIndex(int index, int val) {
if (index < 0 index > size) return; // 如果 index 在索引之外,直接返回
ListNode pre = Head;
for (int i = 0; i < index; i++) pre = pre.next; // 循环遍历,找到插入位置的前一个节点
ListNode node = new ListNode(val); // 拿到前一个节点,下面执行的是插入操作
node.next = pre.next;
pre.next = node;
size++;
}
// 删除链表指定 index 的元素
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) return; // 如果 index 在索引之外,直接返回
ListNode prev = Head;
for (int i = 0; i < index; i++) prev = prev.next; // 循环遍历,找到删除位置的前一个节点
ListNode node = prev.next; // 拿到前一个节点,下面执行的是删除操作
prev.next = node.next;
node.next = null;
size--;
}
}
6 双指针问题 - 环形链表
这是LeetCode
的141题,题目是要找到链表中的环形,题目比较容易,比较形象的解释了双指针的移动,还有很多进阶题目,有兴趣可以去尝试做一下
6.1 题目描述
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos
是 -1
,则在该链表中没有环。
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
分析题目,我们可以定义两个指针来进行移动,slow
指针每次移动一个节点,fast
指针每次移动两个节点,这样就变成了追击相遇,如果链表中有环,fast
指针最后一定会遇到 slow
指针
6.2 code
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) return false;
ListNode node = head.next;
while (node.next != null && node.next.next != null) {
if (node == head) return true;
head = head.next;
node = node.next.next;
}
return false;
}
}
7 写在最后
链表这部分的代码,一定要自己去写,尤其是指针变换的部分很容易让自己绕进去,所以一定要仔细梳理一下,把知识变成自己的才可以,要加油呀~