C# 为什么可以';我做currentNode=currentNode.Next.Next?

C# 为什么可以';我做currentNode=currentNode.Next.Next?,c#,C#,我制作了自己的单链/链表。 现在,如果我想从列表中删除/删除节点/项目,我必须执行以下操作: public void Delete(PARAMETERS) { Node previousNode = null, currentNode = f; while (currentNode != null) { if (SOMECONDITION) { if (previousNode == null)

我制作了自己的单链/链表。 现在,如果我想从列表中删除/删除节点/项目,我必须执行以下操作:

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;
    }
}
(...)
        while ()
        {
            if (SOMECONDITION)
            {
                currentNode = currentNode.Next;
            }
            currentNode = currentNode.Next;
        }
(...)
如果SOMECONDITION为true,您只需跳过currentNode,从而有效地“删除”该节点,因为不再有任何东西指向它

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

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;
    }
}
(...)
        while ()
        {
            if (SOMECONDITION)
            {
                currentNode = currentNode.Next;
            }
            currentNode = currentNode.Next;
        }
(...)
或许:

(...)
        while ()
        {
            if (SOMECONDITION)
            {
                currentNode = currentNode.Next.Next;
            }
            else
            {
                currentNode = currentNode.Next;
            }
        }
(...)
我缺乏什么基本的理解?

做:

currentNode = currentNode.Next.Next;
是NullReferenceException的主要候选对象

编辑: 下面是一些图片的列表实现,可以帮助您理解。

在这两种情况下,您如何知道
currentNode.Next
不为空,因此可以对其应用
.Next
?您只是在检查
!=循环条件中为空。

没有什么可以说您不能执行下一步。下一步

唯一的问题是currentNode.Next是否为空?然后你会得到一个错误


PreviousNode之所以有效,是因为您在使用它之前进行了空检查。

对currentNode和PreviousNode的赋值不会改变链表的结构。它们只是用来跨过结构


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

currentNode只是一个临时指针变量(引用),它不再存在于范围的末尾(即下一个右括号)。当你改变那个参考点的时候,你不会改变任何其他的参考;更改currentNode不会神奇地更改前一个节点的下一个引用点

currentNode = currentNode.Next // only changes the temporary reference
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;
}
您必须实际进入链接列表并更改列表中的引用,这是您在更改previousNode时所做的操作。下一步-更改前一个节点认为其下一个节点的节点。您基本上告诉它“这是您的下一个新节点,忘掉旧节点”


另外,正如其他人所说的,您应该在整个过程中检查空引用。如果currentNode.Next是列表中的最后一个节点,那么它的Next将不指向任何内容,并且您将得到一个NullReferenceException。

如果您想知道类似这样的问题,您应该为链接列表绘制一幅图。要想了解完成链表突变需要做些什么,要比找出原因容易得多。

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

如果这是一个标准链表(每个节点都有下一个,但仅此而已),请按照以下步骤运行单个项目的删除:

步骤1:找到要删除的目标节点,但要跟踪以前访问的节点。
步骤2:prevNode.Next=targetNode.Next


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

如果您重新写入原始内容,您可能会更好地了解您对列表的实际操作

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;
}

您已经在评论中询问了周围的人,以了解列表和下一个列表的属性的更多信息,因此,下面是:

假设列表为:1 | 3 | 5 | 7,第一个指向1,1的下一个属性指向3,5的下一个指向7,7的下一个指向null。这就是存储列表所需跟踪的全部内容。如果将5的下一个属性设置为null,则删除7。如果将3的下一个属性设置为7,则将从列表中删除5。如果将first设置为3,则删除1


这都是关于第一个和下一个属性的。这就是列表的组成部分。

但是为什么previousNode.Next会更改结构?分配给previousNode.Next(或currentNode.Next)会更改结构,因为它会更改变量引用的节点中的Next属性。直接分配给previousNode或CurrentNode只会更改引用,而不会更改对象本身。很明显,我没有得到一些基本的东西。为什么previous.next可以更改列表的结构?Currentnode指向f,但previous开始指向previous。更改previous的值不应影响Currentnode或列表:-s例如,我整天都在看这个,我越来越困惑自己,这再一次让我困惑,为什么我不能只执行Currentnode=Currentnode.Next.Next,从而执行Skipb,因为每次循环时Currentnode的值都会更改,指向列表中的下一个节点。在第一个代码段中,您使用“currentNode=currentNode.Next”作为while循环中的最后一项操作在列表中前进,但您想知道为什么不能使用完全相同的表达式来完成其他操作…但这是否意味着您不能这样做?或者,如果你应用下一个,你不只是需要在你的代码中做一个空检查吗?下一个练习同样,我真的可以给你一些关于如何正确地做这件事的更多说明,以及关于上一个节点的更多说明well@CasperT通常在链表中,删除方法类似于:Remove(Node nodeToRemove),您似乎正在删除一系列节点?从技术上讲,我认为它不会改变任何东西,但列表是一种数据结构,因此无论其中存储了什么,其行为都应该是相同的。就我个人而言,我会迭代列表,然后调用Remove(Node)来删除我想要删除的内容。好了,伙计们,明确的答案在我答案中的注释中。我认为这一切都是由于一个错误,从那时起,它揭示了一些误解,并指出了错误的方向的OP。我不认为有更多的事情要做,除了实现我们自己的修复,我不认为这会对OP有任何好处-我相信OP将能够做到这一点,所有的澄清我张贴在那里。在一个链接列表中,你有很多节点对象与下一个引用每个。参考是一个“指向”另一个ob的变量
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;
}