为什么我不能做currentNode = currentNode.Next.Next?

时间:2009-09-21 20:41:12

标签: c#

我制作了自己的单链/链表。 现在,如果我想从列表中删除/删除节点/项目,我必须做这样的事情:

public void Delete(PARAMETERS)
{
    Node previousNode = null, 
        currentNode = f;
    while (currentNode != null)
    {
        if (SOMECONDITION)
        {
            if (previousNode == null)
            {
                f = currentNode.Next;
            }
            else
            {
                previousNode.Next = currentNode.Next;
            }
        }
        else
        {
            previousNode = currentNode;
        }
        currentNode = currentNode.Next;
    }
}

如果SOMECONDITION为真,你只需跳过currentNode就可以有效地“删除”节点,因为没有任何东西可以指向它。

但是,我真的很想知道,为什么我不能做这样的事情:

(...)
        while ()
        {
            if (SOMECONDITION)
            {
                currentNode = currentNode.Next;
            }
            currentNode = currentNode.Next;
        }
(...)

或许:

(...)
        while ()
        {
            if (SOMECONDITION)
            {
                currentNode = currentNode.Next.Next;
            }
            else
            {
                currentNode = currentNode.Next;
            }
        }
(...)

我缺乏什么基本理解?

8 个答案:

答案 0 :(得分:6)

这样做的:

currentNode = currentNode.Next.Next;

是NullReferenceException的主要候选者

编辑: 这是一个列表实现,其中包含一些可能有助于您理解的图片。 http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=176

答案 1 :(得分:3)

currentNode只是一个临时指针变量(引用),它不再存在于作用域的末尾(即下一个右括号)。当您更改引用所指向的内容时,您不会更改任何其他引用;改变currentNode不会神奇地改变前一节点的Next参考指向的内容。

currentNode = currentNode.Next // only changes the temporary reference

您必须实际进入链接列表并更改列表中的引用,这是您在更改previousNode时所执行的操作。接下来 - 您更改上一个节点认为其下一个节点的节点。你基本上告诉它“这是你的新下一个节点,忘了旧节点。”

此外,正如其他人所说,你应该检查整个空引用。如果currentNode.Next是列表中的最后一个节点,则它的Next将指向任何位置,并且您将获得NullReferenceException。

答案 2 :(得分:2)

没有什么可说的,你不能做Next.Next。

唯一的问题是如果currentNode.Next为null?然后你会得到一个错误。

PreviousNode可以正常工作,因为您在使用之前进行了NULL检查。

答案 3 :(得分:1)

也许如果你重新写一下原文,你会更好地看到你在列表中做了什么。

public void Delete(PARAMETERS)
{
    var previous = FindPreviousNode(PARAMETERS);
    if( previous == null && Matches(f, PARAMETERS)) {
      f = f.Next;
    } else if(previous != null ) {
      previous.Next = previous.Next.Next;
    } // u could add "else { throw new NodeNotFound() }" if that's appropiate
}
private Node FindPreviousNode(PARAMETERS) {
    Node currentNode = f;
    while (currentNode != null) {
        if (Matches(currentNode.Next, PARAMETERS)) {
            return currentNode;
        }
        currentNode = currentNode.Next;
    }
    return null;
}

你已经在评论中询问了解更多关于列表和Next的属性的内容,所以在这里:

让我们说列表是:1 | 3 | 5 | 7,第一个指向1,1的下一个属性指向3,5个下一个指向7,而7的下一个指向空。这就是你追踪存储列表的全部内容。如果将5的Next属性设置为null,则删除7.如果您将3的Next属性设置为7,则从列表中删除5。如果您先设置为3,则删除1。

关于第一个和下一个属性的全部内容。这就是列表的原因。

答案 4 :(得分:0)

在这两种情况下,你怎么知道currentNode.Next不为null,因此你可以在它上面应用.Next?您只是在循环条件中检查!= null。

答案 5 :(得分:0)

currentNode和previousNode的赋值不会改变链表的结构。它们只是用于逐步完成结构。

对previousNode.Next的赋值是改变结构的原因。执行currentNode = currentNode.Next.Next将跳过下一个节点(如果currentNode.Next不为null),但它不会改变列表的结构。

答案 6 :(得分:0)

如果你想知道这样的问题,你应该真正勾勒出链表的图片。 要完成某些链表突变需要做什么要容易得多,而不是推理它。

答案 7 :(得分:0)

老实说,我根本不遵守发布的代码。

如果这是标准链接列表(每个节点都有一个Next,但就是这样),请按照以下步骤删除单个项目:

步骤1:找到要删除的目标节点,但跟踪上一个访问过的节点 第2步:prevNode.Next = targetNode.Next

注意:需要进行删除列表头部的特殊检查。