链表理论基础
链表的节点定义:
// 单链表
struct ListNode {
int val; // 节点上存储的元素
ListNode *next; // 指向下一个节点的指针
ListNode(int x) : val(x), next(NULL) {} // 节点的构造函数
};
通过自己定义构造函数初始化节点:
ListNode* head = new ListNode(5);
使用默认构造函数初始化节点:
ListNode* head = new ListNode();
head->val = 5;
使用默认构造函数,初始化时不能直接给变量赋值。
203.移除链表元素
重点
让节点next指针直接指向下下一个节点就可以了。弹头节点往往需要单独处理,比较麻烦,设置一个虚拟头结点再进行删除操作,统一逻辑。
代码
- 不用虚拟头节点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
while(head!=NULL&&head->val==val){
ListNode *tmp=head;
head=head->next;
delete tmp;
}
ListNode *cur=head;
/*这么写也通过了,while判断后的那次循环就不会再判断
while(cur!=NULL&&cur->next!=NULL){
while(cur!=NULL&&cur->next!=NULL&&cur->next->val==val){
ListNode *tmp=cur->next;
cur->next=cur->next->next;
delete tmp;
}
cur=cur->next;
}
*/
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;
}
};
- 用虚拟头节点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyhead=new ListNode();
dummyhead->next=head;
ListNode* cur=dummyhead;
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;
}
}
//head可能被删了,要重新指向,不然就是操作未知区域
head=dummyhead->next;
delete dummyhead;
return head;
}
};
以后就一律使用虚拟头节点。
707.设计链表
题目链接
设计链表的五个接口:
- 获取链表第index个节点的数值
- 在链表的最前面插入一个节点
- 在链表的最后面插入一个节点
- 在链表第index个节点前面插入一个节点
- 删除链表的第index个节点
代码
class MyLinkedList {
public:
struct ListNode{
int val;
ListNode* next;
ListNode(int x):val(x),next(NULL){}
ListNode(int x ,ListNode* next):val(x),next(next){}
};
int size;
ListNode* dummyhead;
MyLinkedList() {
size=0;
dummyhead=new ListNode(0);
}
int get(int index) {
if(index<0||index>size-1){
return -1;
}
else{
ListNode* cur=dummyhead;
for(int i=0;i<index;i++){
cur=cur->next;
}
return cur->next->val;
}
}
void addAtHead(int val) {
ListNode* tmp=new ListNode(val);
tmp->next=dummyhead->next;
dummyhead->next=tmp;
size++;
}
void addAtTail(int val) {
ListNode* cur=dummyhead;
while(cur->next!=NULL){
cur=cur->next;
}
ListNode* tmp=new ListNode(val);
cur->next=tmp;
size++;
}
void addAtIndex(int index, int val) {
if(index<0) index=0;
if(index>size){//第一次写错了,index=size的时候也是可以的
return ;
}
else{
ListNode* cur=dummyhead;
for(int i=0;i<index;i++){
cur=cur->next;
}
ListNode* tmp=new ListNode(val);
tmp->next=cur->next;
cur->next=tmp;
size++;
}
}
void deleteAtIndex(int index) {
if(index<0||index>size-1){
return;
}
else{
ListNode* cur=dummyhead;
for(int i=0;i<index;i++){
cur=cur->next;
}
ListNode* tmp=new ListNode(0);
tmp=cur->next;
cur->next=cur->next->next;
delete tmp;
tmp=nullptr;
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);
*/
206.反转链表
重点
普通双指针法:这道题不用虚拟头节点了,因为反转后头结点指向空了。要翻转的节点是cur,cur的前一个节点定义为pre,在cur要指向pre之前,要把 cur->next 节点用tmp指针保存一下。
递归法:我的理解是和普通双指针法思路一样,但是主函数里要有一个函数作为启动节点,参数值是最初的;调用的函数作为功能实现,要有循环条件(翻转完指针的移动)和终止条件(和普通双指针法思路一样)。递归法还是要在多理解一下。
代码
- 普通双指针法
/**
- Definition for singly-linked list.
- struct ListNode {
- int val;
- ListNode *next;
- ListNode() : val(0), next(nullptr) {}
- ListNode(int x) : val(x), next(nullptr) {}
- ListNode(int x, ListNode *next) : val(x), next(next) {}
- };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur=head;
ListNode* pre=nullptr;
while(cur!=nullptr){
ListNode* tmp=cur->next;
cur->next=pre;
pre=cur;
cur=tmp;
}
return pre;
}
};
- 递归法
class Solution {
public:
ListNode* reverse(ListNode* cur,ListNode* pre){//别忘了返回类型
//终止条件
if(cur==nullptr){
return pre;
}
//函数功能,反转
ListNode* tmp=cur->next;
cur->next=pre;
//return一个循环条件
// pre = cur;
// cur = temp;
return reverse(tmp,cur);
}
ListNode* reverseList(ListNode* head) {
//直接return,里面写启动条件
// ListNode* cur = head;
// ListNode* pre = NULL;
return reverse(head,nullptr);
}
};