• 【剑指offer】面试题13、在 O(1)时间上删除链表结点


    题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。链表结点与函数的定义如下:
    typedef struct Node
    {
        int m_nValue;
        struct Node *m_pNext;
    }ListNode, *pListNode;
    
    void DeleteNode(ListNode **pHead, ListNode *pToBeDeleted);

      在单链表中删除一个结点,最常用的做法莫过于从链表的头结点开始,顺序遍历查找并找到要删除的结点,然后再进行删除操作。

      比如在下图(a)所示的链表中,我们想要删除结点 i,我们就可以从头结点开始遍历该链表,遍历到 h 结点时,会发现 h 的下一个结点 i 就是我们所要删除的结点。这样我们可以把 h 的 m_pNext指向 i 的下个结点 j。指针调整之后我们就可以安全删除结点 i 并保证链表没有断开

    这种顺序查找的时间复杂度为 O(n)。

     

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

    那么是不是一定需要得到被删除结点的前一个结点呢?答案是否定的。以上面(a)链表为例。我们可以很方便的得到要删除结点 i 的下一个结点 j。如果我们把下一个结点 j 的内容复制到欲删除结点 i 上,再把下个结点 j 删除,这样不就相当于把当前需要删除的结点 i 删除了么【实际删除的为结点 j 】。

    上述思路还有个问题:如果我们要删除的结点位于链表的尾部呢。那么它就没有下个结点。这样我们就需要从链表的头结点开始,进行顺序遍历并删除。

    最后还有一点:除了上面两种情况,还有个特例。就是链表中只有一个结点。上面的两种情况我们在进行删除操作时,不需要删除头结点而当只有一个结点时,我们不仅要删除函数给出的结点pToBeDeleted,同时还要将链表的头结点设置为NULL

    完整的代码如下:

      1 // deleteNode.c
      2 #include "stdio.h"
      3 #include "stdlib.h"
      4 
      5 #define N 10
      6 
      7 typedef struct Node
      8 {
      9     int m_nValue;
     10     struct Node *m_pNext;
     11 }ListNode, *pListNode;
     12 
     13 void deleteNode(ListNode **pHead, ListNode *pToBeDeleted);
     14 // 获得要删除结点
     15 ListNode *getNodeIndex(ListNode *pHead, int index);
     16 
     17 void createList(ListNode **pHead, int len)
     18 {
     19     ListNode *pTail = NULL;
     20 
     21     while(len--)
     22     {
     23         ListNode *pNew = (ListNode*)malloc(sizeof(ListNode));
     24         pNew->m_nValue = rand()%100;
     25         pNew->m_pNext = NULL;
     26 
     27         if(*pHead == NULL)
     28         {
     29             *pHead = pNew;
     30             pTail = pNew;
     31         }
     32         else
     33         {
     34             pTail->m_pNext = pNew;
     35             pTail = pNew;
     36         }
     37     }
     38 }
     39 
     40 void printList(ListNode *pHead)
     41 {
     42     while(pHead != NULL)
     43     {
     44         printf("%3d ", pHead->m_nValue);
     45         pHead = pHead->m_pNext;
     46     }
     47     printf("
    ");
     48 }
     49 
     50 void deleteNode(ListNode **pHead, ListNode *pToBeDeleted)
     51 {
     52     if(!pHead || !pToBeDeleted)
     53         return;
     54 
     55     // 链表有多个结点,并且删除的不是尾结点
     56     if(pToBeDeleted->m_pNext != NULL)
     57     {
     58         ListNode *pNext = pToBeDeleted->m_pNext;
     59         pToBeDeleted->m_nValue = pNext->m_nValue;
     60         pToBeDeleted->m_pNext = pNext->m_pNext;
     61 
     62         free(pNext);
     63         pNext = NULL;
     64     }
     65     // 还剩两种情况:要么链表只有一个结点,要么删除的是尾结点(含有多个结点)
     66     else if(*pHead == pToBeDeleted)// 链表只有一个结点
     67     {
     68         free(pToBeDeleted);
     69         pToBeDeleted = NULL;
     70         *pHead = NULL;
     71     }
     72     else // 多个结点,并且删除的是尾结点
     73     {
     74         ListNode *curNode = *pHead;
     75         while(curNode->m_pNext != pToBeDeleted) // 找到删除结点的前一个结点
     76             curNode = curNode->m_pNext;
     77 
     78         curNode->m_pNext = NULL;
     79         free(pToBeDeleted);
     80         pToBeDeleted = NULL;
     81     }
     82 }
     83 
     84 ListNode *getNodeIndex(ListNode *pHead, int index)
     85 {
     86     if(!pHead || index < 0)
     87         return NULL;
     88 
     89     ListNode *node = pHead; 
     90     while(--index)
     91         node = node->m_pNext;
     92     return node;
     93 }
     94 
     95 int main(int argc, char const *argv[])
     96 {
     97     ListNode *pHead = NULL;
     98 
     99     createList(&pHead, N);
    100     printf("Before: ");
    101     printList(pHead);
    102 
    103     ListNode *pToBeDeleted = getNodeIndex(pHead, 3);
    104     deleteNode(&pHead, pToBeDeleted);
    105     printf("After: ");
    106     printList(pHead);
    107 
    108     return 0;
    109 }
    View Code

    本文完。

  • 相关阅读:
    CodeForces 219D Choosing Capital for Treeland (树形DP)
    POJ 3162 Walking Race (树的直径,单调队列)
    POJ 2152 Fire (树形DP,经典)
    POJ 1741 Tree (树的分治,树的重心)
    POJ 1655 Balancing Act (树的重心,常规)
    HDU 2196 Computer (树形DP)
    HDU 1520 Anniversary party (树形DP,入门)
    寒门子弟
    JQuery选择器(转)
    (四)Web应用开发---系统架构图
  • 原文地址:https://www.cnblogs.com/xfxu/p/4585373.html
Copyright © 2020-2023  润新知