函数 removeElements 删除单链表中所有结点值等于 val 的结点,并返回新的头结点。其中链表头结点为 head,则横线处填写( )。
// 结点结构体
struct Node {
int val;
Node* next;
Node() : val(0), next(nullptr) {}
Node(int x) : val(x), next(nullptr) {}
Node(int x, Node* next) : val(x), next(next) {}
};
Node* removeElements(Node* head, int val) {
Node dummy(0, head); // 睡结点,统一处理头结点
Node* cur = &dummy;
while (cur->next != nullptr) {
if (cur->next->val == val) {
________________ // 在此处填入代码
} else {
cur = cur->next;
}
}
return dummy.next;
}A.
Node* del = cur;
cur = del->next;
delete del;B.
Node* del = cur->next;
cur->next = del;
delete del;C.
Node* del = cur->next;
cur->next = del->next;
delete del;D.
Node* del = cur->next;
delete del;
cur->next = del->next;根据上下文和C++语法规则确定空缺处应填的内容,关注函数调用参数、表达式和返回值类型。
填空时注意语法完整性:分号、括号匹配、函数参数类型和个数、返回值类型。
【考点】链表遍历|哑结点技巧|指针操作顺序
1. 🎯 考纲定位 本题考查 GESP 五级“指针与内存管理”与“链表基本操作”的交叉点。命题人特意把“删除头结点”的场景用哑节点(dummy node)包装,卡住的是那些只背“头结点单独处理”结论、不懂“哑节点统一处理”通法的考生。这一行代码其实是在考“如何安全地跳过链表节点”——这是指针操作中最容易出错的细节。
2. 🧠 解题思维 看到哑节点 dummy 和 cur = &dummy,立刻明白这是为了“统一处理头结点”——不用单独判断 head 是否为空或是否要删。循环里 cur->next 就是当前要检查的结点,一旦值等于 val,就要“跳过”它:让 cur->next 指向 cur->next->next。删除结点时,必须先用临时指针保存被删结点(避免删除后取不到 next),再修改前驱指针,最后 delete。这一类“链表删除某个值”的题,通法永远是:哑节点 + 指针遍历 + 临时指针保存被删结点 + 修改前驱 + 释放。
3. 🪤 陷阱拆解 A 把 cur 指向哑节点删了(cur = del->next 后 del 是哑节点),直接破坏链表头;B 把 cur->next 赋值给自己(cur->next = del),等于没删;D 先 delete del 再访问 del->next,这是悬空指针必挂。最阴险的是 D:你一看“删除结点”就想到 delete,但链表里删除必须“先改指针再删”,否则释放了结点就取不到它的后继。如果你只背结论、不理解本质,就会掉进这个陷阱。
4. 🔄 反命题思维 命题人如果改成“删除所有值等于 val 的结点且 val 是链表最后一个结点的值”,那 cur->next 就是 nullptr,循环条件 cur->next != nullptr 会自动退出,不用额外处理。刷到类似题先问:哑节点是不是真的“哑”?如果直接 head 开始删,头结点会丢,所以必须用哑节点。