虚拟头结点
一、题源:
203. 移除列表元素
问题描述
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
二、 思路:
1、直接操作
从头节点开始遍历,判断指针指向的下一个节点值等不等于val,等于的话,执行删除下个节点的操作
参考代码如下
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* ptr = head, *deletePtr;
if(!ptr) return head;
while(ptr->next)
{
if(ptr->next->val == val)
{
deletePtr = ptr->next;
ptr->next = deletePtr->next;
free(deletePtr);
}
else ptr = ptr->next;
}
if(head->val == val)
{
deletePtr = head;
head = deletePtr->next;
free(deletePtr);
}
return head;
}
时间复杂度:
O
(
n
)
O(n )
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
2、虚拟头节点
上面的方法需要额外考虑头节点,可以通过引入虚拟头节点来使删除操作的代码统一。
参考代码如下
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* headNode = (struct ListNode*)malloc(sizeof(struct ListNode));
headNode->next = head;
struct ListNode* ptr = headNode, *deletePtr;
while(ptr->next)
{
if(ptr->next->val == val)
{
deletePtr = ptr->next;
ptr->next = deletePtr->next;
free(deletePtr);
}
else ptr = ptr->next;
}
head = headNode->next;
free(headNode);
return head;
}
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
三、相关题目及C语言实现
24. 两两交换链表中的节点
问题描述:
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
实现:
struct ListNode* swapPairs(struct ListNode* head){
struct ListNode* headNode = (struct ListNode*)malloc(sizeof(struct ListNode));
headNode->next = head;
struct ListNode* cur, * node1,* node2;
cur = headNode;
while(cur->next && cur->next->next)
{
node1 = cur->next;
node2 = cur->next->next;
cur->next = node2;
node1->next = node2->next;
node2->next = node1;
cur = node1;
}
head = headNode->next;
free(headNode);
return head;
}
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
19. 删除链表的倒数第 N 个结点
问题描述:
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
实现:
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode* headNode = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* slow, * fast;
headNode->next = head;
slow = headNode;
fast = headNode;
for(int i = 0; i < n; i++)fast = fast->next;
while(fast->next)
{
slow = slow->next;
fast = fast->next;
}
fast = slow->next;
slow->next = fast->next;
free(fast);
head = headNode->next;
free(headNode);
return head;
}
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
四、总结
虚拟头节点适用于插入和删除链表结点的问题,这样可以避免对头结点做特殊判断和处理。