必须用 new 而非 malloc,因 new 调用构造函数初始化 next 为 nullptr,malloc 仅分配内存致 next 未定义而崩溃;头插 O(1)、尾插 O(n) 且需维护 tail 指针;insertAfter 前须判空 node;delete 前须重连前驱 next 并置 curr 为 nullptr 防悬垂指针。

怎么用 new 给链表新增节点(别直接 malloc)
在 C++ 里给链表加节点,必须用 new 而不是 malloc——前者会调用构造函数,后者只分配内存,对象没初始化,后续访问 next 或成员变量大概率崩。
常见错误现象:Segmentation fault 出现在第一次访问新节点的 next 字段;或者插入后遍历突然跳过节点,其实是 next 是未定义值。
-
Node* newNode = new Node;—— 最安全,自动调用默认构造函数,next初始化为nullptr(前提是构造函数写了) - 如果没写构造函数,
next是随机值,必须显式赋值:newNode->next = nullptr; - 别写
Node* newNode = (Node*)malloc(sizeof(Node));,C++ 里它绕过类型系统,且不调构造函数
头插法和尾插法的区别在哪(指针操作本质)
头插简单、快,O(1);尾插要遍历到末尾,O(n),但顺序符合直觉。关键不是“怎么写”,而是“谁改了谁的 next”。
使用场景:频繁插入且不关心顺序 → 头插;需要保持插入顺序或后续做队列 → 尾插(建议额外维护 tail 指针)。
立即学习“C++免费学习笔记(深入)”;
- 头插:新节点
next指向原head,再把head改成新节点 —— 两步缺一不可,顺序不能反 - 尾插:找到当前
tail,设tail->next = newNode,再更新tail = newNode;如果没维护tail,就得从head开始 while 到nullptr - 漏掉更新
tail是尾插最常踩的坑,会导致下次尾插仍插在老位置
为什么 insertAfter(node, value) 容易空指针崩溃
这个操作本身不难,但调用前几乎没人检查 node 是否为 nullptr,或者 node 是否是有效链表节点(比如已 delete 过)。
错误现象:core dumped 卡在 node->next = newNode; 这一行;或者插入后链表断成两截。
- 必须先判空:
if (!node) return;,否则解引用空指针 - 别假设传进来的
node一定在链表里——它可能是栈上临时变量,也可能是野指针 - 正确做法:把
newNode->next = node->next;放在第一句,再写node->next = newNode;,避免中间状态丢失后继
delete 节点时为什么不能只写 delete ptr
只写 delete ptr 是释放内存没错,但如果不把前驱节点的 next 指针置空或重连,就会留下悬垂指针(dangling pointer),后续访问直接 UB。
性能影响不大,但逻辑错位极难调试——你以为删了,其实链表结构还在,只是某个 next 指向了已释放内存。
- 删节点前,必须知道它的前驱(头节点要单独处理)
- 典型流程:找到前驱
prev,执行prev->next = curr->next;,再delete curr; - 删完立刻把
curr设为nullptr(虽不解决根本问题,但能帮调试时早暴露误用)
链表真正麻烦的从来不是“怎么加”,而是“加完之后谁负责清理、什么时候清理、清理后谁还持有旧指针”。这些细节不盯住,跑几天才崩一次,比当场报错更难搞。











