题目:给定单链表的头指针和一个结点指针,定义一个函数,在 O(1) 时间删除该节点。ios
分析:在单向链表中删除一个节点,最常规的作法无疑是从链表的头结点开始,顺序遍历查找要删除的节点并在链表中删除该节点。以下图,这种思路因为须要顺序查找,时间复杂度天然是 O(N)。函数
之因此须要从头开始查找,是由于须要找到被删除节点的前一个节点,在单向链表中,因为没有指向前一个节点的指针,只好从链表的头结点开始顺序查找。spa
然而是否是必定要获得被删除的节点的前一个节点呢?答案是否认的。咱们能够方便的获得要删除节点的下一个节点,若是将下一个节点的内容复制到须要删除的节点上,覆盖原有的内容,再把下一个节点删除,就至关于把当前须要删除的节点删除了。指针
这个思路有一个问题,若是要删除的节点位于链表的尾部,那么它就没有下一个节点。此时,咱们仍然须要从链表的头结点开始,顺序遍历获得该节点的前序节点,并完成删除操做。内存
最后注意的是:若是链表中只有一个节点,而又要删除链表的头结点(也就是尾节点),此时在删除节点以后,须要把链表的头指针设置为 NULL。ci
//在O(1) 的时间内,删除单链表节点
#include<iostream>
using namespace std;路由
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}ListNode, *LinkList;it
LinkList InitializeLinkList(LNode *L)
{
if(L == NULL)
{
L = new LNode();
L->next = NULL;
}io
return L;
}stream
void InsertLinkList(LinkList L, ElemType value)
{
if(L == NULL)
return;
LNode *p, *tmp;
tmp = L;
p = new LNode();
p->data = value;
p->next = tmp->next;
tmp->next = p;
}
void PrintLinkList(LinkList L)
{
if(L->next == NULL)
return;
LNode *p;
p = L->next;
while(p != NULL)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
void DeleteNode(ListNode *pListHead, ListNode *pToDeleted)
{
if(!pToDeleted || !pListHead)
return;
//要删除的节点不是尾节点
if(pToDeleted->next != NULL)
{
ListNode *pNext = pToDeleted->next;
pToDeleted->data = pNext->data;
pToDeleted->next = pNext->next;
delete pNext;
pNext = NULL;
}
//链表只有一个节点,删除头结点(也就是尾节点)
else if(pListHead == pToDeleted)
{
delete pToDeleted;
pToDeleted = NULL;
pListHead = NULL;
}
//链表中有多个节点,删除尾节点(此时要遍历单链表)
else
{
ListNode *pNode = pListHead;
while(pNode->next != pToDeleted)
{
pNode = pNode->next;
}
pNode ->next = pToDeleted->next;
delete pToDeleted;
pToDeleted = NULL;
}
}
int main()
{
LNode *L;
L = NULL;
L = InitializeLinkList(L);
int value;
while(cin >> value)
{
InsertLinkList(L, value);
}
PrintLinkList(L);
ListNode *pToDeleted = L->next;
for(int i = 0; i < 4; i++)
{
pToDeleted = pToDeleted->next;
}
DeleteNode(L, pToDeleted);
PrintLinkList(L);
system("pause");
return 0;
}
分析时间复杂度:对于 n - 1 个非尾节点而言,能够在 O(1) 时把下一个节点的内存复制附带要删除的节点,并删除下一节点;对于尾节点而言,因为仍然须要顺序查找,时间复杂度是 O(N),所以,总的时间复杂度为 [(n - 1) * O(1) + O(N)] / N, 结果仍是O(1)。
可是,该方法是基于一个假设:要删除的节点的确存在于链表中。