今天,带来链表相关算法的讲解。文中不足错漏之处望请斧正!
理论基础点这里
移除链表元素
1. 思路
链表的删除和插入,都是改变链接关系。
如图:要删除值为2的结点,要找到其上一个节点,让上一个节点指向值为3的结点。
但这是一个单链表,我们怎么找到上一个呢?只好用一个cur指针从头开始走,cur→next就是可能要删除的节点。
1.1 在原链表删除
我们还需要考虑边界情况:删除头结点。此时只要让head向后走。
但是,这样我们的删除方法就不统一了,头结点是一种删法,其他结点又是另一种删法,容易让代码变多,逻辑也不够简单。
1.2 虚拟头结点
想要统一其实很简单,我们最重要的就是找上一个,但是要删除头结点的时候找不到上一个,那就再给一个虚拟头结点,让它指向真正头结点。头结点就有“上一个结点”了。
此时,dummyhead→next其实就是真正的head,删除方法也能统一。
2. 参考代码
原链表删除
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode *dying = nullptr;
// 移除头部需移除的元素
while (head != nullptr && head->val == val) {
dying = head;
head = head->next;
delete dying;
}
// cur不可能是需要移除的元素,需要移除的元素只可能是cur->next
ListNode *cur = head;
while (cur != nullptr && cur->next != nullptr) {
if (cur->next->val == val) {
dying = cur->next;
cur->next = cur->next->next;
delete dying;
} else {
cur = cur->next;
}
}
return head;
}
};
需要注意:当我们删除某个节点时,cur不需要变,下一次要探测的结点恰好就是cur→next→next。
虚拟头节点
class Solution {
public:
ListNode* removeElements(ListNode* head, int val)
{
ListNode* dummy = new ListNode(-1, head);
ListNode* cur = dummy;
while(cur->next)
{
if(cur->next->val == val)
{
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
else cur = cur->next;
}
ListNode* result = dummy->next;
delete dummy;
return result;
}
};
设计链表
1. 思路
链表操作我们都了解了,就是修改某些节点之间的链接关系,按题目要求做即可。这里实现带虚拟头节点的链表。
2. 参考代码
class MyLinkedList {
public:
MyLinkedList() {
_dummy = new ListNode(-1);
_size = 0;
}
void print() {
ListNode *cur = _dummy->__next;
while (cur) {
cout << cur->__val << " ";
cur = cur->__next;
}
cout << endl;
}
int get(int index) {
if (index >= _size) return -1;
ListNode *cur = _dummy->__next;
for (int i = 0; i < index; ++i) cur = cur->__next;
return cur->__val;
}
void addAtHead(int val) {
ListNode *newNode = new ListNode(val, _dummy->__next);
_dummy->__next = newNode;
++_size;
}
void addAtTail(int val) {
ListNode *tail = _dummy;
while (tail->__next != nullptr) tail = tail->__next;
ListNode *newNode = new ListNode(val);
tail->__next = newNode;
++_size;
}
// 将一个值为 val 的节点插入到链表中下标为 index 的节点之前
void addAtIndex(int index, int val) {
if (index > _size) return;
ListNode *prev = _dummy;
for (int i = 0; i < index; ++i) prev = prev->__next;
ListNode *newNode = new ListNode(val, prev->__next);
prev->__next = newNode;
++_size;
}
void deleteAtIndex(int index) {
if (index >= _size) return;
ListNode *prev = _dummy;
ListNode *cur = prev->__next;
for (int i = 0; i < index; ++i) {
prev = cur;
cur = cur->__next;
}
ListNode *dying = cur;
prev->__next = cur->__next;
delete dying;
--_size;
}
private:
struct ListNode {
int __val;
ListNode *__next;
ListNode(int val, ListNode *next = nullptr)
: __val(val), __next(next) {}
};
private:
ListNode *_dummy;
size_t _size;
};
今天的分享就到这里了,感谢您能看到这里。
这里是培根的blog,期待与你共同进步!