关键点——删除头结点方式:
1.单独判断删除的是否为头结点,并单独处理;
2.增加虚拟头结点,统一所有结点的处理方式;
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
while(head!=NULL && head->val==val){//单独处理头结点
ListNode* temp=head;
head=head->next;
delete temp;
}
ListNode* cur=head;
while(cur!=NULL && cur->next!=NULL){
if(cur->next->val==val){
ListNode* tmp=cur->next;
cur->next=cur->next->next;
delete tmp;
}
else {
cur=cur->next;
}
}
return head;
}
};
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* vhead=new ListNode(0);//如何构建新节点
vhead->next=head;
ListNode* cur=vhead;
while(cur->next!=NULL){
if(cur->next->val==val){
ListNode* tmp=cur->next;
cur->next=cur->next->next;
delete tmp;
}else{
cur=cur->next;
}
}
//记得删除额外的虚拟节点
head=vhead->next;
delete vhead;
return head;
}
};
class MyLinkedList {
public:
struct LinkedNode{
int val;
LinkedNode* next;
LinkedNode(int val):val(val),next(nullptr){} //???
};
MyLinkedList() {
_dummyHead=new LinkedNode(0);//定义虚拟头结点
_size=0;
}
int get(int index) {
//
if(index>_size-1 || index<0){
return -1;
}
LinkedNode* cur=_dummyHead->next;
while(index--){
cur=cur->next;
}
return cur->val;
}
void addAtHead(int val) {
LinkedNode* newNode=new LinkedNode(val);
newNode->next=_dummyHead->next;
_dummyHead->next=newNode;
_size++;
}
void addAtTail(int val) {
LinkedNode* newNode=new LinkedNode(val);
LinkedNode* cur=_dummyHead;
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) {
//
if(index>=_size||index<0){
return ;
}
LinkedNode* cur=_dummyHead;
while(index--){
cur=cur->next;
}
LinkedNode* tmp=cur->next;
cur->next=cur->next->next;
delete tmp;
tmp=nullptr; //tmp被删除后,若不进行赋空值,则会成为野指针
_size--;
}
private://记得定义
int _size;
LinkedNode* _dummyHead;
};
设计链表的五个接口:
- 获取链表第index个节点的数值
- 在链表的最前面插入一个节点
- 在链表的最后面插入一个节点
- 在链表第index个节点前面插入一个节点
- 删除链表的第index个节点
整体步骤:
范围限定->遍历定位->对应操作->善后处理(长度,头结点,野指针)
内容量相比之前要大一点,但是基础经典,必须要会,需要多巩固重复。
双指针法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur=head;
ListNode* pre=nullptr;
ListNode* temp;
while(cur){
temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
}
};
新点:
NULL与nullptr区别——NULL在C++中就是0,C++11加入了nullptr,可以保证在任何情况下都代表空指针 ;
利用temp定位下一个转向的节点,防止前面在翻转时,找不到下一个节点;
从前往后翻转节点指向;
其他2种方法:递归法、从后向前翻转法
class Solution {
public:
ListNode* reverse(ListNode* pre,ListNode* cur){
if(cur==NULL) return pre;
ListNode* temp=cur->next;
cur->next=pre;
return reverse(cur,temp);
}
ListNode* reverseList(ListNode* head) {
return reverse(NULL,head);
}
};
将双指针法进行递归简化
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL) return NULL;
if(head->next==NULL) return head;
ListNode* last=reverseList(head->next);
head->next->next=head;
head->next=NULL;
return last;
}
};
利用递归进行从后往前翻转指针方向