插入节点前必须检查头指针是否为空,空链表头插可与非空链表统一处理为newNode->next = head; head = newNode;,但尾插必须区分空链表(等价头插)与非空链表(需遍历至末尾)。
很多初学者在写 insert 时直接对 head->next 操作,结果一运行就 Segmentation fault。根本原因是没判断 head 是否为 nullptr,尤其在空链表中插入首个节点时,head 本身就是空的,不能解引用。
实操建议:
if (head == nullptr) { head = newNode; return; }
dummy->next 开始,且最终返回的是 dummy->next,不是 dummy
newNode->next = head; head = newNode;,比条件分支更简洁安全三种插入方式看似只是位置不同,但指针修改顺序和依赖关系完全不同。错一步,就会丢节点或成环。
常见错误现象:插入后原链表“消失”、新节点没连上、next 指向随机地址(未初始化)。
实操建议:
newNode->next = head;,再更新 head = newNode; —— 顺序不能反,否则会丢失原链表curr != nullptr && curr->next != nullptr),然后 curr->next = newNode;;别忘了 newNode->next = nullptr;,否则可能指向脏内存pos-1 个节点(如插在索引 2 处,要停在索引 1 节点),再执行 newNode->next = prev->next; prev->next = newNode;
C++ 中 new 在内存不足时默认抛出 std::bad_alloc,但若用了 new(std::nothrow),则返回 nullptr。不检查就直接用,等于埋雷。
实操建议:
Node* newNode = new Node(val); if (newNode ==nullptr) { throw std::runtime_error("Failed to allocate node"); }
Node* makeNode(int val) { auto p = new Node(val); if (!p) throw std::bad_alloc{}; return p; }
new 后不处理异常,导致部分节点插入、部分失败,链表处于中间断裂状态如果链表类里维护了 size_ 成员,每次插入都必须 ++size_;否则 size() 返回值永远不准。另外,C++ 标准库没有链表迭代器失效规则可套用——自实现链表中,插入操作本身不使其他节点指针失效,但若用户缓存了某节点指针并期望它“始终有效”,要注意:该指针仍有效,但其逻辑位置可能已变(比如头插后,原来第一个节点变成第二个)。
实操建议:
++size_,包括构造首个节点时begin()/end() 迭代器接口,插入不改变已有节点地址,所以不触发迭代器失效;但不要假设“插入后某个迭代器仍指向‘当前第 n 个’元素”,因为链表结构已变size_ 和遍历输出,快速验证是否漏更新或逻辑错位实际写插入函数时,最容易被忽略的是:空链表头插与非空链表头插,代码可以完全一致,不需要 if 分支;但尾插必须区分空链表(此时等价于头插)和非空链表(需遍历),这个分支躲不开,也别硬凑成一种写法。