题目一:203. 移除链表元素
要移除节点值为val的节点,需要拥有遍历链表的临时指针变量
因为需要断开val所在节点的前后键,所以要把cur指向val节点前一个,不断地去判断cur->next->val
在删除val节点时,要将其提前存储为临时指针变量,否则重新连键之后就找不到val节点了
构造虚拟头节点的思想:使得原本的第一个节点也能遍历得到,否则还得特殊判断第一个节点的val值,构造头节点使代码更加简洁。
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead = new ListNode(0,head);
ListNode* cur = dummyHead; // 定义一个临时指针cur去遍历
while(cur !=nullptr&&cur->next != nullptr){
if(cur->next->val == val){ //需要断前后键,所以把当前指针cur指向val节点的前一个点
ListNode* tmp = cur->next; // 临时存val节点,为了后面去删掉它
cur->next = cur->next->next;
delete tmp;
}else{
cur = cur->next;
}
}
// 注意head也有可以被删了
// 所以要用虚拟头节点去找链表的新头
head = dummyHead->next;
delete dummyHead,cur;
return head;
}
题目二:707. 设计链表
实现功能:

leetcode上,需要自己实现一个链表类MyLinkedList,包含上述方法。
首先这个MyLinkedList类需要包含两个私有成员变量:int类型的 _size, 和LinkedNode*类型的 _dummyhead,只要有了指向虚拟头节点的指针就可以标记这个链表了。
然后这个LinkedNode节点类型需要自己去定义,包含这个节点的值,和下一个节点的指针

注意:当我们在函数里声明一个节点的时候,一定要用new LinkedNode(val) ,这样才能在堆里为这个节点分配空间,然后返回一个指向这个堆空间的指针。如果不用new的话,采用普通构造出的变量是栈区变量,会随着函数结束而收回的。
完整代码:
class MyLinkedList {
struct LinkedNode{
int val;
LinkedNode* next;
LinkedNode(int val):val(val),next(nullptr){};
};
private:
int _size;
LinkedNode* _dummyhead;
public:
MyLinkedList() { // 注意构造时,_dummyhead和_size 是如何赋值得
_dummyhead = new LinkedNode(0);
_size = 0;
}
int get(int index) {
// 判断index是否合理
if (index > (_size - 1) || index < 0) {
return -1;
}
// 虚拟头节点的下一个节点是index为0的节点
LinkedNode* cur = _dummyhead->next;
while(index--){
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
LinkedNode* NewNode = new LinkedNode(val);
_dummyhead->next = NewNode;
_size++;
}
void addAtTail(int val) {
LinkedNode* NewNode = new LinkedNode(val);
LinkedNode* cur = _dummyhead;
// 定位cur到最后一个有效节点
while(cur->next!=nullptr){
cur = cur->next;
}
cur->next = NewNode;
_size++;
}
void addAtIndex(int index, int val) {
if(index > _size) return;
if(index < 0) index =0;
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyhead;
while(index--){
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
void deleteAtIndex(int index) {
// 判断index是否合理
if (index >= _size || index < 0) {
return ;
}
// 虚拟头节点的下一个节点是index为0的节点
LinkedNode* cur = _dummyhead->next;
while(index--){
cur = cur->next;
}
LinkedNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
_size--;
}
};
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList* obj = new MyLinkedList();
* int param_1 = obj->get(index);
* obj->addAtHead(val);
* obj->addAtTail(val);
* obj->addAtIndex(index,val);
* obj->deleteAtIndex(index);
*/
我们希望cur指向index-1,因为链表在插入和删除任何一个节点的时前后键都要更改,所以把遍历指针定位在index-1位置,这是链表不同于数组的点。从dummyhead开始遍历,可以找到这个index-1位置。如果从index=0位置开始遍历,cur指针就会指向index位置。
题目三: 206. 反转链表
定义一个快指针,用于遍历节点,定义一个慢指针,用来连接键。
循环的结束条件:cur指向空 cur遍历全部节点
要想把链表翻转是一定要定义两个指针的,画图可以看出
注意tmp节点是用来存储cur之后节点的,因为当cur-》next指向pre时,如果不保存tmp以后就找不到了。
ListNode* reverseList(ListNode* head) {
ListNode* tmp;
ListNode* pre = NULL; // pre定义为空可以直接就把最后一个节点指向空
ListNode* cur = head;
while(cur){ //最后一次循环是最后一个节点
tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
//fast->next = slow;
//delete slow;
return pre; // 返回慢指针!!而不是快指针!!
}

总结:今天是day8,才完成day3的任务,继续补作业了。最近阳了好难受。
链表部分没有我想象的那样做得熟练,但是至少是有思路的,经常会卡小bug,要多多练习的。