在 O(1) 时间删除单链表结点

题目:给定单链表的头指针和一个结点指针,定义一个函数,在 O(1) 时间删除该节点。

分析:在单向链表中删除一个节点,最常规的做法无疑是从链表的头结点开始,顺序遍历查找要删除的节点并在链表中删除该节点。如下图,这种思路由于需要顺序查找,时间复杂度自然是 O(N)。

152935_rdFU_2260265.jpg

    之所以需要从头开始查找,是因为需要找到被删除节点的前一个节点,在单向链表中,由于没有指向前一个节点的指针,只好从链表的头结点开始顺序查找。

    然而是不是一定要得到被删除的节点的前一个节点呢?答案是否定的。我们可以方便的得到要删除节点的下一个节点,如果将下一个节点的内容复制到需要删除的节点上,覆盖原有的内容,再把下一个节点删除,就相当于把当前需要删除的节点删除了。

  这个思路有一个问题,如果要删除的节点位于链表的尾部,那么它就没有下一个节点。此时,我们仍然需要从链表的头结点开始,顺序遍历得到该节点的前序节点,并完成删除操作。

    最后注意的是:如果链表中只有一个节点,而又要删除链表的头结点(也就是尾节点),此时在删除节点之后,需要把链表的头指针设置为 NULL。

 

//在O(1) 的时间内,删除单链表节点
#include<iostream>
using namespace std;

typedef int ElemType;
typedef struct LNode
{
 ElemType data;
 struct LNode *next;
}ListNode, *LinkList;

LinkList InitializeLinkList(LNode *L)
{
 if(L == NULL)
 {
  L = new LNode();
  L->next = NULL;
 }

 return L;
}

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)。

但是,该方法是基于一个假设:要删除的节点的确存在于链表中。

 

转载于:https://my.oschina.net/u/2260265/blog/342400

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值