📅  最后修改于: 2023-12-03 15:22:44.436000             🧑  作者: Mango
当面临删除链表中间元素时,我们需要考虑删除的节点究竟是哪个,因为链表的中间节点数可能为偶数或奇数。以下是我们将要讨论的方案:
对于有奇数个节点的链表,中间节点就是第 n/2 + 1 个节点,其中 n 是链表中节点的总数。对于有偶数个节点的链表,我们取中间的两个节点中的任意一个作为中间节点。下面的示例演示了删除链表中间节点的方法:
public ListNode deleteMiddleNode(ListNode head) {
if (head == null) {
return null;
}
if (head.next == null) {
return null;
}
ListNode slow = head;
ListNode fast = head;
ListNode prev = null;
while (fast != null && fast.next != null) {
fast = fast.next.next;
prev = slow;
slow = slow.next;
}
prev.next = slow.next;
return head;
}
上述代码中,我们使用双指针法,其中第一个指针每次向前移动一个节点,第二个指针则每次向前移动两个节点。当第二个指针到达链表末端时,第一个指针就指向了中间节点。通过保留删除节点的前驱节点,我们可以使用 prev.next = slow.next
代码语句来删除中间节点。
有时候我们需要删除中间节点的前驱节点。这种情况通常发生在删除双向链表(doubly linked list)中的某个节点时。下面的代码演示了如何删除链表中间节点的前驱节点:
public ListNode deletePrevOfMiddleNode(ListNode head) {
if (head == null) {
return null;
}
if (head.next == null) {
return null;
}
ListNode slow = head;
ListNode fast = head;
ListNode prev = null;
while (fast != null && fast.next != null) {
fast = fast.next.next;
prev = slow;
slow = slow.next;
}
prev.prev.next = prev.next;
if (prev.next != null) {
prev.next.prev = prev.prev;
}
return head;
}
在上述代码中,我们不仅需要保留删除节点的前驱节点,还需要记录前驱节点的前驱节点(即 prev.prev
)。通过 prev.prev.next = prev.next
代码语句,我们可以跳过要删除的前驱节点(同时将其前驱节点的 next 指针直接指向其后继节点)。如果被删除的前驱节点这时此节点后面还有后继节点的话,还需要更新此后继节点的 prev 指针。
有时候我们需要删除中间节点的后继节点。以下是如何实现该操作的示例代码:
public ListNode deleteSuccOfMiddleNode(ListNode head) {
if (head == null) {
return null;
}
if (head.next == null) {
return null;
}
ListNode slow = head;
ListNode fast = head;
ListNode prev = null;
while (fast != null && fast.next != null) {
fast = fast.next.next;
prev = slow;
slow = slow.next;
}
if (slow.next != null) {
slow.next = slow.next.next;
}
return head;
}
上述代码中,我们只需要更改被删除节点的后继节点的位置即可。通过使用 slow.next = slow.next.next
代码语句,我们就可以直接删除中间节点的后继节点。
我们可以使用上述任何一种方法来删除链表中间节点。具体取决于我们需要删除节点的前驱节点还是后继节点。