面试13:在O(1)时间删除链表结点
题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点。链表结点的定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
函数的声明如下:
void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted);
Google 面试题
在链表中删除一个结点,最常规的做法是从链表的头结点开始,顺序查找要删除的结点,找到之后再删除。由于需要顺序查找,时间复杂度自然就是O(n) 了。我们之所以需要从头结点开始查找要删除的结点,是因为我们需要得到要删除的结点的前面一个结点。
O(1)时间复杂度
如果要删除结点i,先把i的下一个结点j的内容复制到i,然后把i的指针指向j的下一个结点,此时再删除j,其效果刚好是吧结点i给删除了。O(1)
如果要删除的结点位于链表的尾部,没有下一个结点,仍需要从头开始遍历得到该节点的前序节点,并完成删除操作。O(n)
如果链表中只有一个结点,而我们又要删除链表的头结点,也是尾结点,此时删除结点之后,需要把链表的头结点设置为NULL.
平均时间复杂度为[O(1) * (n - 1) + O(n)] / n = O(1)
///
// Delete a node in a list
// Input: pListHead - the head of list
// pToBeDeleted - the node to be deleted
///
void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted)
{
if(!pListHead || !pToBeDeleted)
return;
// if pToBeDeleted is not the last node in the list
if(pToBeDeleted->m_pNext != NULL)
{
// copy data from the node next to pToBeDeleted
ListNode* pNext = pToBeDeleted->m_pNext;
pToBeDeleted->m_nKey = pNext->m_nKey;
pToBeDeleted->m_pNext = pNext->m_pNext;
// delete the node next to the pToBeDeleted
delete pNext;
pNext = NULL;
} else if(pListHead == pToBeDeleted) {
delete pToBeDeleted;
pToBeDeleted = NULL;
pListHead = NULL;
}
// if pToBeDeleted is the last node in the list
else
{
// get the node prior to pToBeDeleted
ListNode* pNode = pListHead;
while(pNode->m_pNext != pToBeDeleted)
{
pNode = pNode->m_pNext;
}
// deleted pToBeDeleted
pNode->m_pNext = NULL;
delete pToBeDeleted;
pToBeDeleted = NULL;
}
}
上述代码基于一个假设:要删除的结点的确在链表中。