【发布时间】:2011-03-15 12:42:49
【问题描述】:
我正在研究如何在双向链表的第一个节点之前插入一个新节点。我对此操作所需的辅助节点以及执行该操作的步骤顺序感到困惑。我将不胜感激有关如何解决此问题的提示,即我的 insertBeforeFirst 方法有什么问题。就目前而言,该方法会导致我发现很难解决的 nullPointerException。 (注意:这是之前post 的后续。)
public DLL()
{
header = null ;
tail = null ;
}
...
DLL myList = new DLL() ;
DLLNode A = new DLLNode("Hello", null, null) ;
DLLNode B = new DLLNode("Hi", null, null) ;
...
myList.addFirst(A) ;
myList.insertBeforeFirst(B)
...
public void addFirst(DLLNode v)
{
v.pred = header ;
v.succ = tail ;
header = v ;
tail = v ;
}
...
public void insertBeforeFirst(DLLNode v)
{
DLLNode aux = v ;
aux.succ = header.succ ;
header = aux ;
DLLNode aux2 = aux.succ ;
aux2.pred = v ;
}
[编辑]
我听从了 Aaron 的建议并画了一张图,我有一点改进,因为我不再收到 nullPointerException,但是新模式插入到第一个节点之后而不是之前。所以我认为我的绘画技巧也需要一些打磨:)
public void insertBeforeFirst(DLLNode v)
{
v.succ = header.succ ; // point new node succ to current first node
header.succ = v ; //point header to new node
DLLNode aux = header.succ ; // auxiliary node for backward insertion
aux.pred = v ; // point auxiliary's pred backward to new node
}
[EDIT2]
看看 MahlerFive 的帖子,我现在明白了为什么你们中的一些人可能会对我的头尾谈话感到困惑。这是我从这里得到的:“为了简化编程,在双向链表的两端添加特殊节点很方便:在列表头部之前添加一个 header 节点,和一个 trailer 节点就在列表的尾部。这些“虚拟”节点不存储任何元素” source
因此,对于初学者来说,我似乎需要找到一种方法来正确实现这些虚拟节点,然后才能添加任何内容并进行正确的引用。这些 DUMMY 节点似乎需要不同的 Node 构造函数?它们可以由 DLL 默认构造函数实例化吗?
[EDIT3]
@MahlerFive,DLL 构造函数将如下所示:
public DLL()
{
DLLNode Header = new DLLNode(null, null, null) ;
DLLNode Tail = new DLLNode(null, Header, null) ;
Header.succ = Tail ;
}
我的方法是这样的,虽然我现在得到一个 nullPointerException:
// insert z before v
public void addBeforeFirst(DLLNode v, DLLNode z)
{
DLLNode aux = v.pred ;
z.pred = aux ;
z.succ = v ;
v.pred = z ;
aux.succ = z ;
}
[EDIT4]
我正在进步。 (感觉很棒!)我同意 MahlerFive 的观点,即 DUMMY Header 和 Tail 节点不是解决这个问题的好方法。但正如在一本出版的书中提到的那样,它至少值得探索。这是我的新代码(不使用虚拟节点):
...
// DLL Constructor
public DLL()
{
first = null ;
last = null ;
}
...
// example insert call
// B is the node in front of which i want to insert
l.insert("Ciao", B) ;
...
public void insert(String elem, DLLNode pred)
{
// make ins a link to a newly-created node with element elem,
// predecessor null, and successor null.
DLLNode ins = new DLLNode(elem, null, null) ;
// Insert ins at the insertion point in the
// forward SLL headed by first.
ins.pred = first ;
ins.succ = first ;
// let first be the the new node
first = ins ;
}
这需要微调,因为我还没有设置任何反向链接,但这是一个很好的起点。为确保它正常工作(至少以正向方式),我添加了打印语句以在添加节点时打印出第一个和最后一个元素。事实上,它们已正确更新:
Hi
first: hi
last: hi
Ciao Hi
first: Ciao
last: hi
Moin Ciao Hi
first: Moin
last: hi
【问题讨论】:
-
“虚拟节点”是解释列表头部和尾部的一种非常糟糕的方式。您引用的虚拟节点的定义基本上是“没有数据的普通节点”。但是这是错误的。头节点应该有pred吗?尾巴有成功吗?您可以像使用普通节点一样添加或删除虚拟节点吗?没有。实际上,您应该将头部和尾部视为列表头部和尾部的实际节点的引用或“指针”。您有一个带有头和尾引用的 DLL 对象,这是处理此问题的标准方法。
-
我编辑了我的答案以响应您的编辑#3
-
你已经接近了。现在,在每一步之后准确地画出你列出的样子。你应该注意到一些问题。如果没有,请尝试从尾部向后打印列表(在 pred 引用之后),您应该会注意到一个问题。
标签: java linked-list