当前位置: 首页 > news >正文

刷题笔记:力扣第707题-设计链表

1.本题是一道链表综合性题目,基本上将链表的所有操作全都考察了一遍,以下是写出的完整代码:

1. typedef struct MyLinkedList{ 2. int val; 3. struct MyLinkedList* next; 4. } MyLinkedList; 5. 6. // 创建链表,初始化虚拟头节点 7. MyLinkedList* myLinkedListCreate() { 8. // 分配虚拟头节点内存 9. struct MyLinkedList* dummyHead = (struct MyLinkedList*)malloc(sizeof(struct MyLinkedList)); 10. // 初始链表无有效节点,虚拟头后继置空 11. dummyHead->next = NULL; 12. return dummyHead; 13. } 14. 15. // 获取下标index位置节点的值,无节点返回-1 16. int myLinkedListGet(MyLinkedList* obj, int index) { 17. // cur指向第一个真实节点 18. struct MyLinkedList* cur = obj->next; 19. // 循环移动index次到达目标下标 20. for (int i = 0; i < index; i++){ 21. // 中途链表断裂,下标越界直接返回-1 22. if (cur == NULL){ 23. return -1; 24. } 25. cur = cur->next; 26. } 27. // 循环结束cur为空说明下标不存在,返回-1,否则返回节点值 28. return cur == NULL ? -1 : cur->val; 29. } 30. 31. // 在链表头部插入节点 32. void myLinkedListAddAtHead(MyLinkedList* obj, int val) { 33. // 新建待插入节点 34. struct MyLinkedList* newHead = (struct MyLinkedList*)malloc(sizeof(struct MyLinkedList)); 35. // 新节点后继指向原第一个有效节点 36. newHead->next = obj->next; 37. // 设置节点存储数值 38. newHead->val = val; 39. // 虚拟头指向新节点,完成头插 40. obj->next = newHead; 41. } 42. 43. // 在链表尾部插入节点 44. void myLinkedListAddAtTail(MyLinkedList* obj, int val) { 45. // 创建新尾节点 46. struct MyLinkedList* newTail = (struct MyLinkedList*)malloc(sizeof(struct MyLinkedList)); 47. // 遍历指针从虚拟头出发 48. struct MyLinkedList* cur = obj; 49. // 循环找到链表最后一个节点 50. while (cur->next != NULL){ 51. cur = cur->next; 52. } 53. // 尾节点后继为空 54. newTail->next = NULL; 55. newTail->val = val; 56. // 原尾节点连接新节点 57. cur->next = newTail; 58. } 59. 60. // 在下标index位置插入节点 61. void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) { 62. // 遍历指针从虚拟头开始 63. struct MyLinkedList* cur = obj; 64. // 移动index次,找到插入位置的前驱节点 65. for (int i = 0; i < index; i++){ 66. // 中途指针为空,下标非法直接退出 67. if (cur == NULL){ 68. return; 69. } 70. cur = cur->next; 71. } 72. // 前驱为空,无插入位置直接返回 73. if (cur == NULL){ 74. return; 75. } else { 76. // 新建插入节点 77. struct MyLinkedList* newNode = (struct MyLinkedList*)malloc(sizeof(struct MyLinkedList)); 78. // 新节点连接原index位置节点 79. newNode->next = cur->next; 80. newNode->val = val; 81. // 前驱节点指向新节点,完成插入 82. cur->next = newNode; 83. } 84. 85. } 86. 87. // 删除下标index位置的节点 88. void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) { 89. // 遍历指针从虚拟头出发 90. struct MyLinkedList* cur = obj; 91. // 移动index次找到待删节点的前驱 92. for (int i = 0; i < index; i++){ 93. // 指针为空,下标非法直接退出 94. if (cur == NULL){ 95. return; 96. } 97. cur = cur->next; 98. } 99. // 前驱为空 / 前驱无后继,说明目标节点不存在,直接返回 100. if (cur == NULL || cur->next == NULL){ 101. return; 102. } else { 103. // 保存待删除节点地址 104. struct MyLinkedList* del = cur->next; 105. // 前驱跳过待删节点,重新连接链表 106. cur->next = cur->next->next; 107. // 释放被删除节点内存 108. free(del); 109. } 110. } 111. 112. // 释放整个链表所有节点内存 113. void myLinkedListFree(MyLinkedList* obj) { 114. // cur指向第一个真实节点 115. struct MyLinkedList* cur = obj->next; 116. // 循环销毁每一个有效节点 117. while (cur != NULL){ 118. // 缓存当前待释放节点 119. struct MyLinkedList* del = cur; 120. // 指针先后移,防止断链丢失后续节点 121. cur = cur->next; 122. free(del); 123. } 124. // 最后释放虚拟头节点 125. free(obj); 126. } 127. 128. /** 129. * Your MyLinkedList struct will be instantiated and called as such: 130. * MyLinkedList* obj = myLinkedListCreate(); 131. * int param_1 = myLinkedListGet(obj, index); 132. 133. * myLinkedListAddAtHead(obj, val); 134. 135. * myLinkedListAddAtTail(obj, val); 136. 137. * myLinkedListAddAtIndex(obj, index, val); 138. 139. * myLinkedListDeleteAtIndex(obj, index); 140. 141. * myLinkedListFree(obj); 142. */

2.本道题目思想不难,难点在于诸多小细节,所以花费了很长时间,下面是一些心得:

(1)能使用虚拟头结点就使用虚拟头结点,这样能简化许多操作。

(2)指针越界问题一定要注意,在移动cur指针的时候考虑要所有的情况(例如链表没有任何节点的特殊情况),这时候使用虚拟头结点就能保证至少有一个真实节点,代码就会更容易写出来。

(3)执行链表全部删除操作时,不要忘记释放虚拟头结点的空间。

(4)当需要修改链表结构(插入、删除)时一般令cur = dummyHead,因为需要拿到index的上一个节点,而0号节点的上一个节点正是dummyHead。

(5)当只需要读取数据,不改变链表结构时一般令cur = dummyHead->next,因为只关心真实节点中的数值。

http://www.jsqmd.com/news/1285618/

相关文章:

  • STM32 PWM频率与占空比计算原理:从定时器时钟到参数配置实战
  • 2026年来内蒙古游玩必打卡 这款口碑超好的本土特色鸡品牌一定要尝
  • C语言动态内存通讯录实现:从malloc到realloc的完整项目指南
  • C++内存管理:从基础概念到智能指针与内存池实战
  • 本地部署开源远程桌面网关 Next Terminal 并实现外部访问
  • 标杆案例:仅靠3台设备,如何撑起800人的自救器盲戴考核?
  • IMU模块:从陀螺仪到多传感器融合的姿态感知技术详解
  • Qt自定义控件开发:提升法实战详解与避坑指南
  • 用纸开啤酒瓶:材料力学与杠杆原理的应急生活技巧
  • Meta Quest MR开发实战:用模板缓冲实现虚实融合的门窗效果
  • 智能插座选购配置全攻略:从Wi-Fi协议到自动化场景实战
  • MMDetection v2.22.0 实战:从零训练自定义目标检测模型
  • 金融CSV数据分析:移动均线、异常点检测与收益回撤可视化
  • ESP32开发中模块选择与配置全解析:从硬件识别到环境配置实战
  • Arduino按键自锁与状态机实现:从消抖到稳定状态切换
  • Fluent多孔介质模型:催化器仿真从原理到工程实践全解析
  • PHP扩展安全与无字符RCE绕过:从CTF题看纵深防御
  • 分布式光伏发展现状与选型要点解析
  • Grid++Report脚本实战:5大场景实现动态字段计算与报表逻辑控制
  • Java开发环境搭建:从JDK安装到多版本管理的完整指南
  • 2026 年平乡比较好的集分气缸批发厂家哪个好,这玩意儿竟是工业管道的“隐形心脏”?-智能锅炉 - 鉴选官
  • MAX30100心率血氧模块:从PPG原理到Arduino实现的完整开发指南
  • Otsu算法:从原理到实战,实现图像二值化的自动阈值计算
  • 基于CH554单片机的USB音频播放器设计与实现:PWM DAC方案详解
  • 基于Raft分布式Kv存储:leaderHeartBeatTicker
  • 全球蓄热瓷球市场竞争动态分析及未来前景展望报告2026年版
  • ARM汇编实战:从零点亮LED,深入理解GPIO与内存映射I/O
  • 学嵌入式和C语言编程|第七天:循环嵌套、循环辅助语句与数组
  • 豆包AI商业实战手册:33个副业变现案例解析
  • 十三层大一统模型下华夏六家核心同源体系——气化运化、天人混元完整论证