1、题目:
给定单向链表的头指针和一个节点的指针,定义一个函数在O(1)时间删除该节点。链表节点与函数的定义如下:
struct ListNode
{
int m_value;
ListNode* m_next;
};
void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted);
2、解题思路
2.1、常规解法
从链表的头节点开始,顺序遍历查找要删除的节点,并在链表中删除该节点。如图1(a)所示的链表中,我们要删除节点i,可以从链表的头节点a开始顺序遍历,发现节点h的m_next指向要删除节点i,于是就可以把节点h的m_next指向i的下一个节点即节点j。由于需要顺序查找删除节点,故其时间复杂度为O(n).
图1. 在链表中删除一个节点的两种方法
采用上述方法的主要原因是,我们需要找到被删除节点的前一个节点,而有没有一种方法可以不用得到被删除节点的前一个节点而实现直接删除节点呢?
2.2、O(1)高效方法
我们可以不用得到被删除节点的前一个节点,而直接把被删除节点的下一个节点的内容复制到需要删除的节点上覆盖原来的内容,再把下一个结点删除,实现删除指定节点。如图1(c)所示。
考虑全面:
1、当然如果要删除的节点位于链表的尾部,那么它就没有下一个节点了,这时仍需要从链表的头节点开始,顺序遍历得到该节点的前序节点,并完成删除操作。
2、如果链表中只有一个节点,而我们又要删除链表的头节点(也是尾节点),此时我们在删除节点之后,还需要把链表的头节点设置为NULL。
3、代码实现
//O(1)时间删除链表某一个节点
void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted)
{
if(!*pListHead || !pToBeDeleted)
return;
//如果该删除链表节点不是尾节点
if(pToBeDeleted->m_next != NULL)
{
ListNode *pNextNode=pToBeDeleted->m_next;
pToBeDelted->m_value = pNextNode->m_value;
pToBeDeleted->m_next = pNextNode->m_next;
delete pNextNode;
pNextNode=NULL;
}else if(*pListHead == pToBeDeleted)//链表中只有该一个节点
{
delete pToBeDeleted;
pToBeDeleted=NULL;
*pListHead=NULL;
}else //链表中有多个节点且删除节点恰好是尾节点
{
//顺序查找
ListNode *pNode=*pListHead;
while(pNode->m_next != pToBeDeleted)
{
pNode=pNode->m_next;
}
pNode->m_next=NULL;
delete pToBeDeleted;
pToBeDeleted=NULL;
}
}