day03
链表基本知识
-
链表是通过指针串联在一起的线性结构,每个节点由两部分组成,分别是数据域(存放该节点的数据)和指针域(存放指向下一个节点的指针)。
-
链表的入口节点称为头节点也就是head,链表的最后一个节点指向null。
如图所示:
-
链表类型有:单链表、双链表和循环链表。
单链表的指针域只能指向下一个节点。 而双链表则每个节点都有两个指针域,一个指向前一个节点,一个指向后一个节点。 循环链表则是链表首尾相连的链表。
-
链表的存储方式
和数组不同,链表在内存中并不是连续分布的。链表通过指针域中的指针链接各个节点。
-
链表定义模板(java)
public class ListNode {
int val;
ListNode next;
public ListNode() {}
ListNode(int x) {
this.val = x;
}
ListNode(int x, ListNode next){
this.val = val;
this.next = next;
}
}
- 链表的操作
-
删除节点–> ListNode.next = ListNode.next.next
-
添加节点–> tempNode = ListNode.next; ListNode.next = newNode; newNode.next = tempNode;
例题 leetcode 203.移除链表元素
链接:https://leetcode.cn/problems/remove-linked-list-elements/
思路:遍历链表,找到与val值相等的节点,删除该节点即可。
重点:
删除操作的实现有两种方式:
- 直接使用原来的节点来进行删除操作
- 设置虚拟头节点来进行删除操作
我们使用第二个方法。因为当头节点为需要删除的节点的时候,需要让head = head.next,这和其他节点的删除操作有所不同。
而第二个方法就是能够使用统一的逻辑来删除所有节点的方法。
另外一个需要注意的重点则是在遍历链表的题目中需要关注遍历循环终止的条件,必须要准确才能够完美进行循环!
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummyhead = new ListNode();
dummyhead.next = head;
ListNode temp = dummyhead;
while(temp.next != null){
if(temp.next.val == val){
temp.next = temp.next.next;
}
else{
temp = temp.next;
}
}
return head;
}
}
例题 leetcode 707.设计链表
链接:https://leetcode.cn/problems/design-linked-list/
分析:该题目并不难,但是各个函数的实现以及链表数据结构的本身的实现需要严谨对待。
class MyLinkedList {
ListNode head;
int size;
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
}
public MyLinkedList() {
head = new ListNode(0);
size = 0;
}
public int get(int index) {
if(index >= size || index < 0) return -1;
ListNode dummyhead = head;
while(index >= 0){
dummyhead = dummyhead.next;
index--;
}
return dummyhead.val;
}
public void addAtHead(int val) {
addAtIndex(0,val);
}
public void addAtTail(int val) {
addAtIndex(size, val);
}
public void addAtIndex(int index, int val) {
if(index > size) return;
ListNode pre = head;
while(index > 0){
pre = pre.next;
index--;
}
ListNode toAdd = new ListNode(val);
toAdd.next = pre.next;
pre.next = toAdd;
size++;
}
public void deleteAtIndex(int index) {
if(index >= size || index < 0) return;
ListNode pre = head;
size--;
if (index == 0) {
head = head.next;
return;
}
while(index > 0){
pre = pre.next;
index--;
}
pre.next = pre.next.next;
}
}
例题 leetcode 206.反转链表
链接:https://leetcode.cn/problems/reverse-linked-list/
分析:使用双指针法并不难,需要训练递归方法的实现!
思路:从前往后翻转指针指向
双指针法
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode dummyhead = head;
ListNode temp = null;
while(dummyhead != null){
temp = dummyhead.next;
dummyhead.next = pre;
pre = dummyhead;
dummyhead = temp;
}
return pre;
}
}
递归法
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null, head);
}
private ListNode reverse(ListNode prev, ListNode cur) {
if (cur == null) {
return prev;
}
ListNode temp = null;
temp = cur.next;// 先保存下一个节点
cur.next = prev;// 反转
// 更新prev、cur位置
// prev = cur;
// cur = temp;
return reverse(cur, temp);
}
}