我正在学习关联数据结构,这个概念对我有意义,但代码没有。
我希望有人可以帮我解释一下。
这是演讲幻灯片:
我在这里有一个构造函数:
private static class Node<E> {
private E value;
private Node<E> next;
private Node( E value, Node<E> next ) {
this.value = value;
this.next = next;
}
}
价值 - 存储实际信息。 Next-存储对存储的上一个对象的引用。说得通。
但是......
public void addFirst( E o ) {
Node<E> newNode = new Node<E>( o, null );
if ( head == null ) {
head = newNode;
} else {
newNode.next = head;
head = newNode;
}
}
上面的代码应该是添加元素
但这是我的问题:newNode
已创建。 newNode.next
字段存储对象头的引用。 (顺便说一下,我不知道头部在哪里声明)然后:head=newNode
。
所以Head现在具有newNode
存储的值,而head.next
现在正在引用它自己?
这里的问题是head中的原始值丢失了,并且没有newNode
的引用。
我错过了什么吗?
答案 0 :(得分:0)
简化addFirst:
public void addFirst( E o ) {
head = new Node<E>( o, head );
}
head将被设置为新节点。旧的头部将在head.next
。
答案 1 :(得分:0)
是的,你错过了这个方法叫做addFirst,所以它是在头之前添加元素的方法。这正是真正做的方法。它创建一个新节点,将其设置为下一个,然后更新列表的头部,指向新创建的节点。
由于java是按值传递,因此该代码应该可以正常工作。
答案 2 :(得分:0)
我认为你错过了对象的身份。请考虑以下类及其字段:
List<E>
Node<E> head
Node<E>
E value
Node<E> next
假设您有一个空列表,这意味着有这些对象(实际上只有一个):
List(1)
head = null
为了更好地说明,我给了对象一个唯一的数字。实际上,通过其存储位置明确地识别对象。
现在将"as"
添加到列表中:
Node<E> newNode = new Node<E>( o, null );
List(1)
head = null
Node(2)
value = "as"
next = null
head = newNode;
List(1)
head = Node(2)
Node(2)
value = "as"
next = null
现在添加"df"
:
Node<E> newNode = new Node<E>( o, null );
List(1)
head = Node(2)
Node(2)
value = "as"
next = null
Node(3)
value = "df"
next = null
newNode.next = head;
List(1)
head = Node(2)
Node(2)
value = "as"
next = null
Node(3)
value = "df"
next = Node(2)
head = newNode;
List(1)
head = Node(3)
Node(2)
value = "as"
next = null
Node(3)
value = "df"
next = Node(2)
如您所见,单个节点的值未更改,新head
,Node(3)
未引用自身。 head
的值为"df"
,下一个节点为"as"
,因此确实在现有节点前添加了"df"
。
正如其他人也指出的那样,addFirst
可以大大简化。看看原文:
Node<E> newNode = new Node<E>( o, null );
if ( head == null ) {
head = newNode;
} else {
newNode.next = head;
head = newNode;
}
head = newNode;
行显示在两个if
分支的底部,因此可以将其移出:
Node<E> newNode = new Node<E>( o, null );
if ( head == null ) {
} else {
newNode.next = head;
}
head = newNode;
...将then
分支留空,以便更好地扭转条件:
Node<E> newNode = new Node<E>( o, null );
if ( head != null ) {
newNode.next = head;
}
head = newNode;
仔细观察,在if
之后,newNode.next
将是(旧的)head
,无论if
是否已被执行(然后显而易见)或不执行(构造函数将其设置为null,如果未执行if
,则head
也是null
。所以另一种写这个的方法是:
Node<E> newNode = new Node<E>( o, head );
head = newNode;
现在你有一个只使用过一次的变量:
head = new Node<E>( o, head );
但实际上,以更好的理解方式编写代码,特别是如果您的目标是学习。
答案 3 :(得分:0)
说实话,这个例子肯定缺少一些东西。无论是作者犯了错误,还是想让你仔细思考并填补空白。根据您引用的addFirst方法,需要在定义addFirst方法的类中定义“head”。但Node类示例与其构造函数基本相同。类构造函数将新节点添加到列表的前面(这正是addFirst所做的)。假设没有任何其他数据,addFirst()在定义Node的上下文中没有任何意义。由于Node中的所有定义都是私有的,因此必须有一个包含它的对象(Node可能是一个嵌套类)。
所以也许是这样的:
public class LinkedList<E> {
private class Node<E> {
private E value;
private Node<E> next;
private Node( E value, Node<E> next) {
this.value = value;
this.next = next;
}
}
private Node<E> head;
//Create a linked list
public LinkedList() {
head = null;
}
//Add a node to the front of the list
public void addFirst( E o ) {
Node<E> newNode = new Node<E>( o, head);
head = newNode;
}
}
使用它看起来像:
LinkedList<String> list = new LinkedList<String>();
list.addFirst("A");
list.addFirst("B");
list.addFirst("C");
最终会出现类似“C”的内容 - &gt; “B” - &gt;列表中的“A”。