链表的一系列操作
1.删除列表元素
有以下几个主要步骤:
- 定义虚拟头节点
- 使用虚拟头节点的尾端接入head
- 循环链表查询是否有元素等于目标元素
- 将上一个节点的尾端接入下一个节点的头端
- 删除中间含目标元素的节点
- 将虚拟节点的下一个节点设为头节点
- 输出链表头节点
主要理解难点
- 如果使用原链表的话很有可能头节点无法判断和去除,从而影响结果
while (head != NULL && head->val == val) { // 注意这里不是if
ListNode* tmp = head;
head = head->next;
delete tmp;
}
需要添加一个判断头节点的限制条件
同时,循环的限制条件变成了
while (cur != NULL && cur->next!= NULL) {
因为需要判断头节点是不是空
2. 添加虚拟头节点有助于判断头节点,这一点要多去思考多用
代码如下
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* element = dummyhead;
while (element->next != NULL) {
ListNode* Next = element->next;
if (Next->val == val) {
ListNode *vtu = Next;
element->next = Next->next;
delete vtu;//一定要把节点删掉
} else {
element = element->next;
}
}
head = dummyhead->next;//记得把next变为头节点
return head;
}
};
设计一个链表
链表的设计最主要也是最中心的点就是不能有逻辑漏洞,主要漏洞点有如下:
- 增加和删除链表的时候会有先将原插入点的前一个节点的指针指向新的节点,这样后面节点就丢失了。
- 删除链表和增加链表都要注意size
- while循环很容易出问题,因为while循环中很有可能出现表头或者表尾没有考虑的情况,最好就是每次都想一想表头和表尾的极端情况
- 还有index 的超限情况一定要根据题目看清楚,例如:
if(index > _size) return;
if(index < 0) index = 0;
接下来我把完成的代码放出来
class MyLinkedList {
public:
struct LinkNode {
int val;
LinkNode* next;
LinkNode(int val) : val(val), next(nullptr) {}
};
MyLinkedList() {
_dummyHead = new LinkNode(0);
_size = 0;
}
int get(int index) {
if (index > (_size - 1) || index < 0) {
return -1;
}
LinkNode* cur = _dummyHead->next;
while (index--) {
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
LinkNode* newlink = new LinkNode(val);
newlink->next = _dummyHead->next;
_dummyHead->next = newlink;
_size++;
}
void addAtTail(int val) {
LinkNode* cur = _dummyHead;
while (cur->next != nullptr) {
cur = cur->next;
}
LinkNode* newlink = new LinkNode(val);
cur->next = newlink;
_size++;
}
void addAtIndex(int index, int val) {
if(index > _size) return;
if(index < 0) index = 0;
LinkNode* newlink = new LinkNode(val);
LinkNode* cur = _dummyHead;
while (index) {
cur = cur->next;
index--;
}
newlink->next = cur->next;
cur->next = newlink;
_size++;
}
void deleteAtIndex(int index) {
if (index >= _size || index < 0) {
return;
}
LinkNode* cur = _dummyHead;
while (index) {
cur = cur->next;
index--;
}
LinkNode *deleteindex = cur->next;
cur->next = cur->next->next;
delete deleteindex;
_size--;
deleteindex = nullptr;//一定要变成空指针
}
private:
LinkNode* _dummyHead;
int _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);
*/
链表的倒转
链表的倒转和指针有点像:双指针法
先定义一个null 的指针,再定义一个head 的指针,从而一前一后判定过去
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *cur = head;
ListNode *pre = nullptr;
while (cur != nullptr){
ListNode *nextpart = cur->next;
cur->next = pre;
pre = cur;
cur = nextpart;
}
return pre;
}
};