代码一:class ListNode {
int val;
ListNode next;
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode temp = dummyHead;
while (temp.next != null) {
if (temp.next.val == val) {
temp.next = temp.next.next;
} else {
temp = temp.next;
}
}
return dummyHead.next;
}
}
代码二:class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
size = 0;
head = new ListNode(0);
}
public int get(int index) {
if (index < 0 || index >= size) {
return -1;
}
ListNode cur = head;
for (int i = 0; i <= index; i++) {
cur = cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0, val);
}
public void addAtTail(int val) {
addAtIndex(size, val);
}
public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
index = Math.max(0, index);
size++;
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
ListNode toAdd = new ListNode(val);
toAdd.next = pred.next;
pred.next = toAdd;
}
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
pred.next = pred.next.next;
}
}
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
为什么代码二的第三行写了一句这个 ListNode head; 代码二的head.next才是真正的头节点,head却是一个虚拟节点。代码一却是head就是头节点。
哪位大佬能讲清楚这其中的区别吗
在代码二的 MyLinkedList 类中,我们看到在构造方法中创建了一个新的 ListNode,并将其赋值给 head:
public MyLinkedList() {
size = 0;
head = new ListNode(0);
}
这里,我们创建了一个值为 0 的 ListNode 并将其赋值给 head。这个节点并不包含实际的数据,而只是作为一个占位符。因此,我们称它为虚拟头节点。
虚拟头节点的主要目的是简化链表操作。例如,在执行链表的插入或删除操作时,处理头部节点(第一个实际数据节点)通常需要特殊处理,因为它没有前驱节点。但是,如果我们有一个虚拟头节点,那么头部节点和其他节点就可以使用相同的逻辑来处理。
通过使用虚拟头节点,我们可以在链表的开头添加或删除节点,而不需要编写特殊的逻辑。虚拟头节点的 next 指针指向真正的头节点(即第一个实际数据节点)。由于虚拟头节点始终存在,我们可以确保 head.next 指向链表的第一个实际数据节点,即使链表为空。
所以,当我们说 ListNode head 创建了一个虚拟头节点时,我们实际上是说在 MyLinkedList 类的构造方法中,我们初始化了一个值为 0 的 ListNode,并将其作为虚拟头节点。这样做有助于简化链表操作和处理边界情况。
|