要求

  • 给定单向链表的头指针和一个节点指针,在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分配的对象指针指向的内存,之后还要清空指针才能完成彻底删除

[刷题] 剑指offer 面试题18:删除链表节点的更多相关文章

  1. 剑指offer——面试题18:删除链表的节点

    #include"List.h" void DeleteNode(ListNode** pHead,ListNode* pToBeDeleted) { if(*pHead==nul ...

  2. [刷题] 剑指Offer 面试题7:重建二叉树

    题目:输入某二叉树的前序遍历和中序遍历结果,重建该二叉树.(假设输入的前序和中序遍历结果中都不含重复数字) 思路 构建二叉树的两个函数:Construct().ConstructCore() Cons ...

  3. 剑指Offer面试题:14.链表的倒数第k个节点

    PS:这是一道出境率极高的题目,记得去年参加校园招聘时我看到了3次,但是每次写的都不完善. 一.题目:链表的倒数第k个节点 题目:输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯,本题 ...

  4. 剑指offer 面试题35.复杂链表的复制

    时间O(N),空间O(N) /* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomList ...

  5. 剑指offer(56)删除链表中重复的节点

    一直忘记更新了,把剑指offer更新完吧.... 题目描述 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3-&g ...

  6. 剑指offer——面试题18.1:删除链表中重复的节点

    // 面试题18(二):删除链表中重复的结点 // 题目:在一个排序的链表中,如何删除重复的结点?例如,在图3.4(a)中重复 // 结点被删除之后,链表如图3.4(b)所示. #include &l ...

  7. 剑指Offer:面试题18——树的子结构(java实现)

    问题描述: 输入两棵二叉树A和B,判断B是不是A的子结构.二叉树结点的定义如下: public class TreeNode { int val = 0; TreeNode left = null; ...

  8. 剑指Offer:面试题16——反转链表(java实现)

    问题描述 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后的链表的头结点.链表结点如下: public class ListNode { int val; ListNode next = n ...

  9. 【剑指offer 面试题15】链表中倒数第K个结点

    思路: 定义两个指针同时指向head,第一个指针先走K-1步,随后二个指针同时移动,当第一个指针到末尾处时,第二个指针所指向的即为倒数第K个结点. #include <iostream> ...

随机推荐

  1. Java中的三大特性 - 超详细篇

    前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的三大特性 - 超详细篇>,希望对大家有帮助,谢谢 这一节的内容可能有点多,大家可以选择性的来看 简介 Java的三大特性:封装.继 ...

  2. 基于Hive进行数仓建设的资源元数据信息统计:Hive篇

    在数据仓库建设中,元数据管理是非常重要的环节之一.根据Kimball的数据仓库理论,可以将元数据分为这三类: 技术元数据,如表的存储结构结构.文件的路径 业务元数据,如血缘关系.业务的归属 过程元数据 ...

  3. 全网最值得推荐的ELKB日志学习博客-博客地址留存

    博客地址:https://elasticstack.blog.csdn.net/article/details/102728604 博客地址留存,后续解决疑难问题

  4. [深搜]C. 【例题3】虫食算

    C . [ 例 题 3 ] 虫 食 算 题目解析 正解 : Dfs + 剪枝 依题意,把样例以加法的形式展现出来. 根据加法的性质,可以得出有两种情况:有进位和没有进位的. 而从百位到最高位的结果,又 ...

  5. 答应我,别在go项目中用init()了

    前言 go的 init函数给人的感觉怪怪的,我想不明白聪明的 google团队为何要设计出这么一个"鸡肋"的机制.实际编码中,我主张尽量不要使用init函数. 首先来看看 init ...

  6. 可读性友好的JavaScript:两个专家的故事

    每个人都想成为专家,但什么才是专家呢?这些年来,我见过两种被称为"专家"的人.专家一是指对语言中的每一个工具都了如指掌的人,而且无论是否有帮助,都一定要用好每一点.专家二也知道每一 ...

  7. 火爆外网的 DGS 框架使用

    Netflix 已开放其 Domain Graph Service(DGS)框架的源代码 ,该框架是为了方便整合 GraphQL 使用,用于简化 GraphQL 的实现. GraphQL 主要是作用于 ...

  8. 广告成本控制-PID算法

    今天我们来聊聊广告成本控制中常用的PID算法. 0.PID算法简介 首先我们可以看下维基百科中给PID算法的定义:由比例单元(Proportional).积分单元(Integral)和微分单元(Der ...

  9. 在Win10中手动添加/修改本地IP

    1 前言 好久没动Win10了... 今天需要用Win10做一下实验,手动修改IP,于是写下了这篇文章作为过程记录. 2 概述 Win10里面修改本地IP不是一件特别困难的事,简单来说可以分为两种方式 ...

  10. 反调试——Windows异常-SEH

    反调试--Windows异常-SEH 概念: SEH:Structured Exception Handling SEH是Windows默认的异常处理机制 如何使用 在代码中使用 __try​​__e ...