假设要删除一个链表的第四个节点,p指向第四个节点?
为什么需要指向链表第三个节点的指针?
答案 0 :(得分:0)
您需要引用前一个节点,因为它的下一个指针指向要删除的节点。这显然不能保持这样:需要更新下一个指针以跳过要删除的节点并指向下一个。
如果您只有对要删除的节点的引用,则无法在前一个节点上进行更新——除了从头节点开始在列表中开始新的遍历,以便找回前一个节点并进行更新。
这是一个带有五个节点和值 1、2、3、4 和 5 的链表的可视化:
head
↓
┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 1 │ │ value: 2 │ │ value: 3 │ │ value: 4 │ │ value: 5 │
│ next: ——————→ │ next: ——————→ │ next: ——————→ │ next: ——————→ │ next:null │
└───────────┘ └───────────┘ └───────────┘ └───────────┘ └───────────┘
现在假设您要删除值为 4 的节点(我将其称为节点 4)……那么结果应该是:
head
↓
┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 1 │ │ value: 2 │ │ value: 3 │ │ value: 4 │ │ value: 5 │
│ next: ——————→ │ next: ——————→ │ next: ──────┐ │ next:null │ │ next:null │
└───────────┘ └───────────┘ └───────────┘ │ └───────────┘ └───────────┘
│ ↑
└────────────────────┘
...之后可以释放该节点使用的内存。
这里发生了两件事:
next
指针重定向到节点 5next
指针设置为 NULL
-- 这是可选的,但真正强调的是该节点不再与列表有关系。由于我们需要更改 Node 3 中的某些内容,因此我们需要对其进行引用。当我们只有对节点 4 的引用时,这是一个问题。获得对节点 3 的引用的唯一方法是从 head
开始并从那里跟随 next
指针......直到我们到达节点 3。但那是浪费时间。
然而,如果我们有对节点 3 的引用,那么我们也有对节点 4 的引用:它是位于节点 3 中的 next
指针!因此,当我们只有节点 3 的引用时,我们拥有了执行删除节点 4 所需的一切。
所以一个实现可能看起来像这样——我使用 c:
void delete_after(Node * prev) {
Node * node = prev->next; // get a reference to the node that needs removal
if (node == NULL) return; // Nothing to do
// And here is the reason why we need prev:
prev->next = node->next; // Rewire, skipping the node to delete
node->next = NULL; // optional
free(node);
}
答案 1 :(得分:0)
这里有两种情况:
1 -> 3 -> 6 -> 2 -> 5 -> None
。首先,我们将第 5 个节点复制到第 4 个节点上。该列表现在变为 1 -> 3 -> 6 -> 5 -> 5 -> None
。由于您已经拥有指向第 4 个节点的指针,因此您可以轻松删除第 5 个节点(通过为第 4 个节点设置 node.next = node.next.next)。链表现在看起来像 1 -> 3 -> 6 -> 5 -> None
,我们从原始链表中删除了第 4 个节点,而没有使用指向第三个节点的指针。