链表的虚拟头结点简单应用
在对链表进行操作时,采用虚拟头结点的方法会使得操作简单很多。
例如,在对于链表进行删除操作时(删掉链表中的某个结点),对于头结点以外的结点删除时,是通过其前一个结点直接指向该结点的下一个结点来实现删除该结点的效果。
如上图中,要删除数据域为2的结点,则让它的前驱结点直接指向2结点的后驱结点,然后释放其内存即可。如下图所示。
但是如果要删除的结点是头结点,则不能采取上述操作,因为头结点并没有前驱节点。所以需要单独进行头结点的删除操作。头结点的删除操作如下图所示,将head后移,然后释放掉之前头结点的内存。
当引入虚拟头结点时就可以将头结点和之外结点的删除操作整合起来,只需要一段代码就可以实现两种情况的删除。
当引入了虚拟头结点dummyNode以后,如果要删除头结点1只需要将dummyNode指向结点1的后驱结点,然后释放结点1的内存;这样就将两种情况的删除整合起来了,只需要一种操作就可以实现。
力扣题目203:移除链表元素
如上所述,采用两种方法对于链表的元素进行删除。
1)直接删除
/**
* 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 != nullptr && head->val == val) {
ListNode* temp = head;
head = head->next;
delete temp;
}
ListNode* cur = head;
while (cur != nullptr && cur->next != nullptr) {
if (cur->next->val == val) {
ListNode* temp = cur->next;
cur->next = cur->next->next;
delete temp;
}
else
cur = cur->next;
}
return head;
}
};
2)虚拟头结点进行删除
/**
* 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* dummyNode = new ListNode(0);
dummyNode->next = head;//设置一个虚拟头结点
ListNode* cur = dummyNode;
while (cur->next != nullptr) {
if (cur->next->val == val) {
ListNode* temp = cur->next;
cur->next = cur->next->next;
delete temp;
}
else {
cur = cur->next;
}
}
head = dummyNode->next;
delete dummyNode;
return head;
}
};
总结
在链表的相关操作中,虚拟头结点的方法是很常用的。采用虚拟头结点可以简化很多的操作。