基础知识
链表定义方式
struct ListNode {
int val; // 节点上存储的元素
ListNode *next; // 指向下一个节点的指针
ListNode(int x) : val(x), next(NULL) {} // 节点的构造函数
};
与数组的对比
注意
给定前节点进行删除、插入操作复杂度为O(1),给定编号进行删除、插入操作复杂度为O(n)
移除链表元素
题目
https://leetcode.cn/problems/remove-linked-list-elements/
题解
问题
1.使用原链表进行删除头节点操作时,为何用while而不是if
ListNode* removeElements(ListNode* head, int val) {
// 删除头结点
while (head != NULL && head->val == val) { // 注意这里不是if
ListNode* tmp = head;
head = head->next;
delete tmp;
}
笔记
1.对链表进行查找
while (cur != NULL && cur->next!= NULL){
cur = cur->next;
}
需要先判断cur再判断cur->next,否则会出现空指针的问题。
设计链表
题目
https://leetcode.cn/problems/design-linked-list/
题解
class MyLinkedList {
public:
struct LinkNode{
int val;
LinkNode* next;
LinkNode():val(0),next(nullptr){}
LinkNode(int x):val(x),next(nullptr){}
LinkNode(int x,LinkNode *next):val(x),next(next){}
};
MyLinkedList() {
_dummyHead = new LinkNode(0);
_size = 0;
}
int get(int index) {
if(index > (_size - 1)|| index < 0)
return -1;
int num = 0;
LinkNode *cur = new LinkNode();
cur = _dummyHead->next;//头节点的索引为0
while(cur != NULL)
{
if(num == index)
// if(index == 0)
return cur->val;
cur = cur->next;
// index--;
num ++;
}
return -1;
}
void addAtHead(int val) {
LinkNode *newNode = new LinkNode(val);
newNode->next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
// return _dummyHead;
}
void addAtTail(int val) {
LinkNode *newNode = new LinkNode(val);
LinkNode *cur = new LinkNode();
cur = _dummyHead;
while(cur->next != NULL)
{
cur = cur->next;
}
cur->next = newNode;
_size++;
// return _dummyHead;
}
void addAtIndex(int index, int val) {
// if(index > _size - 1|| index <0)
// return -1;
int num = 0;
LinkNode *newNode = new LinkNode(val);
LinkNode *cur = new LinkNode();
cur = _dummyHead;
while(cur!= NULL)
{
if(num == index)
{
newNode->next = cur->next;
cur->next = newNode;
_size ++;
break;
// return _dummyHead;
}
cur = cur->next;
num ++;
}
}
void deleteAtIndex(int index) {
// if(index > _size - 1|| index <0)
// return -1;
int num = 0;
LinkNode *cur = new LinkNode();
cur = _dummyHead;
while(cur != NULL && cur->next != NULL)
{
if(num == index)
{
// cur->next = newNode;
cur->next = cur->next->next;
_size--;
// return _dummyHead;
}
cur = cur->next;
num ++;
}
}
private:
int _size;
LinkNode* _dummyHead;
};
/**
* 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);
*/
笔记
1.cur指向dummyHead->next 可以使指针直接从链表的第一个节点开始遍历,对于不同的题目可以通过极端例子进行验证,比如在查找第n个节点值时,可以使查找的节点为第0个来判断是否正确或者出现空指针的情况。
2.在查找链表的第n个节点时,不需要对cur->next!=NULL进行判断,因为这个函数只对当前节点进行操作,若加入cur->next!=NULL进行判断,可能会跳过最后一个节点
3.在尾部插入节点,终止条件要明确为最后一个节点,即cur->next == NULL
4.若要求实现在第n个节点前插入,需要保证第n个节点为cur->next,才可以对cur进行操作
5.对于遍历的cur,需要保证cur->next是题目要求的第n个节点,才可以通过对cur进行操作满足题目要求。
反转链表
题目
https://leetcode.cn/problems/reverse-linked-list/
题解
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* temp; // 保存cur的下一个节点
ListNode* cur = head;
ListNode* pre = NULL;
while(cur) {
temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next
cur->next = pre; // 翻转操作
// 更新pre 和 cur指针
pre = cur;
cur = temp;
}
return pre;
}
};
注意:
最后一个节点应为NULL,因此pre不能用构造函数进行初始化,直接赋值为NULL。