[刷题] 剑指offer 面试题18:删除链表节点

要求

  • 给定单向链表的头指针和一个节点指针,在O(1)时间内删除该节点
  • 常规思路:从头节点a开始顺序遍历,发现p指向要删除的节点i,然后把p的m_pNext指向i的下一个节点j,时间复杂度O(n)
  • O(1)的思路:把i的下一个节点j的内容复制到i,然后令i指向j的下一个节点
  • 考虑特殊情况:
    • 链表只有一个节点:删除该节点
    • 删除尾节点:遍历至倒数第二个节点,删除

DeleteNodeList.cpp

  1 #include <cstdio>
  2 #include "List.h"
  3 
  4 void DeleteNode(ListNode** pListHead,ListNode* pToBeDeleted){
  5     if(!pListHead || !pToBeDeleted)
  6         return;
  7     if(pToBeDeleted->m_pNext != nullptr){
  8         ListNode* pNext = pToBeDeleted->m_pNext;
  9         pToBeDeleted->m_nValue = pNext->m_nValue;
 10         pToBeDeleted->m_pNext = pNext->m_pNext;
 11         delete pNext;
 12         pNext=nullptr;
 13     }
 14     else if(*pListHead == pToBeDeleted){
 15         delete pToBeDeleted;
 16         pToBeDeleted = nullptr;
 17         *pListHead = nullptr;
 18     }else{
 19         ListNode* pNode = *pListHead;
 20         while(pNode->m_pNext != pToBeDeleted){
 21             pNode = pNode->m_pNext;
 22         }
 23         pNode->m_pNext = nullptr;
 24         delete pToBeDeleted;
 25         pToBeDeleted = nullptr;
 26     }
 27 }
 28 
 29 void Test(ListNode* pListHead,ListNode* pNode){
 30     printf("The original list is:\n");
 31     PrintList(pListHead);
 32     
 33     printf("The node to be deleted is:\n");
 34     PrintListNode(pNode);
 35     
 36     DeleteNode(&pListHead,pNode);
 37     
 38     printf("The result list is:\n");
 39     PrintList(pListHead);
 40 }
 41 
 42 void Test1(){
 43     ListNode* pNode1 = CreateListNode(1);
 44     ListNode* pNode2 = CreateListNode(2);
 45     ListNode* pNode3 = CreateListNode(3);
 46     ListNode* pNode4 = CreateListNode(4);
 47     ListNode* pNode5 = CreateListNode(5);
 48     
 49     ConnectListNodes(pNode1,pNode2);
 50     ConnectListNodes(pNode2,pNode3);
 51     ConnectListNodes(pNode3,pNode4);
 52     ConnectListNodes(pNode4,pNode5);
 53     
 54     Test(pNode1,pNode3);
 55     
 56     DestroyList(pNode1);
 57 }
 58 
 59 void Test2()
 60 {
 61     ListNode* pNode1 = CreateListNode(1);
 62     ListNode* pNode2 = CreateListNode(2);
 63     ListNode* pNode3 = CreateListNode(3);
 64     ListNode* pNode4 = CreateListNode(4);
 65     ListNode* pNode5 = CreateListNode(5);
 66 
 67     ConnectListNodes(pNode1, pNode2);
 68     ConnectListNodes(pNode2, pNode3);
 69     ConnectListNodes(pNode3, pNode4);
 70     ConnectListNodes(pNode4, pNode5);
 71 
 72     Test(pNode1, pNode5);
 73 
 74     DestroyList(pNode1);
 75 }
 76 
 77 // 链表中有多个结点,删除头结点
 78 void Test3()
 79 {
 80     ListNode* pNode1 = CreateListNode(1);
 81     ListNode* pNode2 = CreateListNode(2);
 82     ListNode* pNode3 = CreateListNode(3);
 83     ListNode* pNode4 = CreateListNode(4);
 84     ListNode* pNode5 = CreateListNode(5);
 85 
 86     ConnectListNodes(pNode1, pNode2);
 87     ConnectListNodes(pNode2, pNode3);
 88     ConnectListNodes(pNode3, pNode4);
 89     ConnectListNodes(pNode4, pNode5);
 90 
 91     Test(pNode1, pNode1);
 92 
 93     DestroyList(pNode1);
 94 }
 95 
 96 // 链表中只有一个结点,删除头结点
 97 void Test4()
 98 {
 99     ListNode* pNode1 = CreateListNode(1);
100 
101     Test(pNode1, pNode1);
102 }
103 
104 // 链表为空
105 void Test5()
106 {
107     Test(nullptr, nullptr);
108 }
109 int main(int argc,char* argv[]){
110     Test1();
111     Test2();
112     Test3();
113     Test4();
114     Test5();
115     return 0;
116 }

List.h

 1 struct ListNode{
 2     int m_nValue;
 3     ListNode* m_pNext;
 4 };
 5 
 6 ListNode* CreateListNode(int value);
 7 void ConnectListNodes(ListNode* pCurrent,ListNode* pNext);
 8 void PrintListNode(ListNode* pNode);
 9 void PrintList(ListNode* pHead);
10 void DestroyList(ListNode* pHead);
11 void AddToTail(ListNode** pHead,int value);
12 void RemoveNode(ListNode** pHead,int value);

List.cpp

 1 #include "List.h"
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 ListNode* CreateListNode(int value){
 6     ListNode* pNode = new ListNode();
 7     pNode->m_nValue = value;
 8     pNode->m_pNext = nullptr;
 9     return pNode;
10 }
11 
12 void ConnectListNodes(ListNode* pCurrent,ListNode* pNext){
13     if(pCurrent == nullptr){
14         printf("Error to connect two nodes.\n");
15         exit(1);
16     }
17     pCurrent->m_pNext = pNext;    
18 }
19 
20 void PrintListNode(ListNode* pNode){
21     if(pNode == nullptr){
22         printf("The node is nullptr\n");
23     }
24     else{
25         printf("The key in node is %d.\n",pNode->m_nValue);
26     }
27 }
28 
29 void PrintList(ListNode* pHead){
30     printf("PrintList starts.\n");
31     ListNode* pNode = pHead;
32     while(pNode != nullptr){
33         printf("%d\t",pNode->m_nValue);
34         pNode = pNode->m_pNext;
35     }
36     printf("\nPrintList ends.\n");
37 }
38 
39 void DestroyList(ListNode* pHead){
40     ListNode* pNode = pHead;
41     while(pNode != nullptr){
42         pHead = pHead->m_pNext;
43         delete pNode;
44         pNode = pHead;
45     }
46 }
47 
48 void AddToTail(ListNode** pHead,int value){
49     ListNode* pNew = new ListNode();
50     pNew->m_nValue = value;
51     pNew->m_pNext = nullptr;
52     if(*pHead == nullptr){
53         *pHead = pNew;
54     }else{
55         ListNode* pNode = *pHead;
56         while(pNode->m_pNext != nullptr)
57             pNode = pNode->m_pNext;
58         pNode->m_pNext = pNew;
59     }
60 }
61 
62 void RemoveNode(ListNode** pHead,int value){
63     if(pHead == nullptr || *pHead == nullptr)
64         return;
65     ListNode* pToBeDeleted = nullptr;
66     if((*pHead)->m_nValue == value){
67         pToBeDeleted = *pHead;
68         *pHead = (*pHead)->m_pNext;
69     }else{
70         ListNode* pNode = *pHead;
71         while(pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue != value)
72             pNode = pNode->m_pNext;
73         if(pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue == value){
74             pToBeDeleted = pNode->m_pNext;
75             pNode->m_pNext = pNode->m_pNext->m_pNext;
76             }
77         }
78         if(pToBeDeleted != nullptr){
79             delete pToBeDeleted;
80             pToBeDeleted = nullptr;
81         }
82 }

总结

  • 操作数据用指针(如修改数据的内容),操作指针用指针的指针(如修改指针的指向)
  • 想要改变一个值,就要先得到它的地址,想要改变一个指针,就要先得到指针的地址(指针的指针)
  • 在.h中定义数据结构体,声明函数;在.cpp中实现函数
  • new和delete配套使用,new申请内存,delete释放new分配的对象指针指向的内存,之后还要清空指针才能完成彻底删除
posted @ 2019-12-12 10:10  cxc1357  阅读(152)  评论(0编辑  收藏  举报