【谷歌面试题】在O(1)时间内删除链表节点

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

函数的声明如下:
void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted);  

分析:这是一道广为流传的Google面试题,能有效考察我们的编程基本功,还能考察我们的反应速度,更重要的是,还能考察我们对时间复杂度的理解。

在链表中删除一个结点,最常规的做法是从链表的头结点开始,顺序查找要删除的结点,找到之后再删除。由于需要顺序查找,时间复杂度自然就是O(n) 了。

我们之所以需要从头结点开始查找要删除的结点,是因为我们需要得到要删除的结点的前面一个结点。我们试着换一种思路。我们可以从给定的结点得到它的下一个结点。这个时候我们实际删除的是它的下一个结点,由于我们已经得到实际删除的结点的前面一个结点,因此完全是可以实现的。当然,在删除之前,我们需要需要把给定的结点的下一个结点的数据拷贝到给定的结点中。此时,时间复杂度为O(1)。

上面的思路还有一个问题:如果删除的结点位于链表的尾部,没有下一个结点,怎么办?我们仍然从链表的头结点开始,顺便遍历得到给定结点的前序结点,并完成删除操作。这个时候时间复杂度是O(n)。那题目要求我们需要在O(1)时间完成删除操作,我们的算法是不是不符合要求?实际上,假设链表总共有n个结点,我们的算法在n-1总情况下时间复杂度是O(1),只有当给定的结点处于链表末尾的时候,时间复杂度为O(n)。那么平均时间复杂度[(n-1)*O(1)+O(n)]/n,仍然为O(1)。

[cpp]  view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. typedef struct LNode{  
  5.     int data;  
  6.     LNode *next;  
  7. }LNode, *List;  
  8.   
  9. void InsertList(List &l, int data)//头插入节点  
  10. {  
  11.     List head;  
  12.     LNode *p=new LNode;  
  13.     p->data=data;  
  14.     if(NULL==l)  
  15.         p->next=NULL;  
  16.     else  
  17.         p->next=l;  
  18.     l=p;  
  19. }  
  20.   
  21. void PrintList(List l)//打印链表  
  22. {  
  23.     LNode *p=l;  
  24.     while(p)  
  25.     {  
  26.         cout<<p->data<<" ";  
  27.         p=p->next;  
  28.     }  
  29.     cout<<endl;  
  30. }  
  31.   
  32. void DeleteNode(List &l, LNode *toBeDeleted)//删除链表l中的toBeDeleted节点  
  33. {  
  34.     LNode *p;  
  35.     if(!l || !toBeDeleted)  
  36.         return;  
  37.   
  38.     if(l==toBeDeleted)//若删除的节点时表头  
  39.     {  
  40.         p=l->next;  
  41.         delete toBeDeleted ;  
  42.         l=p;          
  43.     }  
  44.     else  
  45.     {  
  46.         if(toBeDeleted->next==NULL)//若删除的节点时最后一个节点  
  47.         {  
  48.             p=l;  
  49.             while(p->next!=toBeDeleted)  
  50.                 p=p->next;  
  51.             p->next=NULL;  
  52.             delete toBeDeleted;  
  53.         }  
  54.         else//删除节点时中间节点  
  55.         {  
  56.             p=toBeDeleted->next;  
  57.             toBeDeleted->data=p->data;  
  58.             toBeDeleted->next=p->next;  
  59.             delete p;  
  60.   
  61.         }  
  62.   
  63.     }  
  64.   
  65. }  
  66.   
  67. void main()  
  68. {  
  69.     List l=NULL;  
  70.     LNode *p;  
  71.     int n;  
  72.     InsertList(l, 3);  
  73.     InsertList(l, 7);  
  74.     InsertList(l, 12);  
  75.     InsertList(l, 56);  
  76.     InsertList(l, 33);  
  77.     InsertList(l, 78);  
  78.     InsertList(l, 20);  
  79.     InsertList(l, 89);  
  80.   
  81.     PrintList(l);  
  82.     cout<<"请输入要删除的节点:";  
  83.     cin>>n;  
  84.   
  85.     p=l;  
  86.     while(p->data!=n && p)  
  87.         p=p->next;  
  88.   
  89.     if(!p)  
  90.     {  
  91.         cout<<"不存在这样的节点!"<<endl;  
  92.         return;  
  93.     }  
  94.     else  
  95.         DeleteNode(l, p);  
  96.   
  97.     cout<<"删除后的链表:";  
  98.     PrintList(l);  
  99.   
  100.   
  101.   
  102.       
  103.   
  104. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值