【问题标题】:Singly Linked List Implementation using C# - RemoveLast Method使用 C# 实现单链表 - RemoveLast 方法
【发布时间】:2023-03-02 22:52:02
【问题描述】:

我已经使用 C# 实现了单链表。任何人都可以查看以下代码并提出我错的地方吗?

public int RemoveLast()
{
    if (Head != null)
    {
         var curNode = Head;

         while (curNode.Next != null)
         {
              curNode = curNode.Next;
         }

         var lastNodeValue = curNode.Value;

         curNode = null;
         Size--;
         return lastNodeValue;
     }

     return -1;
}

此函数不会删除最后一个节点。我无法弄清楚出了什么问题。当 while 循环结束时,我们在 curNode 中获得了 next 为 null 的节点的引用。这意味着这是最后一个节点。最后,我将此节点设置为空。但是当我使用显示功能时。它也显示最后一个节点。这不是删除最后一个节点。

这是我的显示功能:

    public string Display()
    {
        if (Head == null)
        {
            return string.Empty;
        }

        var curNode = Head;
        var builder = new StringBuilder();

        while (curNode.Next != null)
        {
            builder.Append($"{curNode.Value} ");
            curNode = curNode.Next;
        }

        builder.Append($"{curNode.Value} ");

        return builder.ToString();
    }

【问题讨论】:

  • 你只是在清除你的 currNode。它不会从列表中删除任何内容。预期的行为。您必须清除 倒数第二个 节点的 Next 属性才能删除最后一个节点。
  • 您不会将 .Next 属性更改为 null。您只是将本地引用更改为 null。
  • 我的猜测是 curNode 是 List 元素的本地副本。不是实际的列表元素。让 curNode 成为一个 var 使得它是什么类型变得模棱两可。您应该用明确的类型化来适当地替换它。 Taht 正是不应该使用 var 的那种情况。
  • 尝试更改您的时间以检查curNode.Next.Next == null 并设置curNode.Next = null
  • @SebastianL 如果 size = 1 怎么办? currNode.Next.Next 会抛出 NPE!

标签: c# singly-linked-list


【解决方案1】:

好的,在你们的帮助下,我重写了这个满足所有要求的方法,如果链表中只有一个节点,则将 HeadNode 设置为 null。所以我们开始:

    public int RemoveLast()
    {
        if (HeadNode != null)
        {
            var currNode = HeadNode;
            var prevNode = HeadNode;

            if (HeadNode.Next == null)
            {
                HeadNode = null;
                Size--;
                return currNode.Value;
            }

            while (currNode.Next != null)
            {
                prevNode = currNode;
                currNode = currNode.Next;
            }

            prevNode.Next = null;
            Size--;
            return currNode.Value;
        }

        return -1;
    }

感谢在此线程中做出贡献的每个人。快乐编码:)

【讨论】:

    【解决方案2】:
    [x] -> [x] -> [x] -> null
                   ^
                   curNode (becomes null)
               ^
               this reference still exists
    

    在执行curNode = null 时,您不会更改列表中的任何引用。 curNode变量只改变了,它指向操作前的最后一个元素,操作后变为null

    尝试始终保持对上一个节点的引用:

    public int RemoveLast()
    {
        if (Head != null)
        {
            var curNode = Head;
            // Corner case when there is only one node in the list
            if (Head.Next == null)
            {
                Head = null;
                Size--;
                return curNode.value;
            }
    
            var beforeLastNode = curNode;
            curNode = curNode.Next;
            while (curNode.Next != null)
            {
                beforeLastNode = curNode;
                curNode = curNode.Next;
            }
    
            var lastNodeValue = curNode.Value;
    
            beforeLastNode.Next = null;
            Size--;
            return lastNodeValue;
        }
    
        return -1;
    }
    

    【讨论】:

      【解决方案3】:

      您需要将前一个节点上的 curNode.Next 值设为 null。 'curNode' 是一个局部变量,将其设置为 null 不会做任何事情,除了可能会延长其 GC 寿命。

      public int RemoveLast()
      {
          if (Head != null)
          {
               var curNode = Head;
               var previousNode = null;
      
               while (curNode.Next != null)
               {
                    previousNode = curNode;
                    curNode = curNode.Next;
               }
      
               var lastNodeValue = curNode.Value;
      
               if (previousNode == null)
                   Head = null;
               else
                   previousNode.Next = null;
               Size--;
               return lastNodeValue;
           }
      
           return -1;
      }
      

      【讨论】:

      • 这里还有:如果 size == 1 怎么办?
      • @Fildor 谢谢。
      【解决方案4】:

      您需要转到最后一个节点,并将其 Next 更改为 null:

      public int RemoveLast()
      {
          if (Head != null)
          {
              var curNode = Head;
      
              while (curNode.Next?.Next != null)
              {
                  curNode = curNode.Next;
              }
      
              var lastNodeValue = curNode.Next?.Value ?? -1;
              curNode.Next = null;
              Size--;
              return lastNodeValue;
          }
      
          return -1;
      }
      

      请注意,如果您还希望将 Head 设置为 null(如果它是唯一节点),那么您可以这样做:

      public int RemoveLast()
      {
          if (Head != null)
          {
              var curNode = Head;
      
              while (curNode.Next?.Next != null)
              {
                  curNode = curNode.Next;
              }
      
              int lastNodeValue;
      
              if (Head.Next == null)
              {
                  lastNodeValue = Head.Value;
                  Head = null;
              }
              else
              {
                  lastNodeValue = curNode.Next?.Value ?? -1;
              }
              curNode.Next = null;
              Size--;
              return lastNodeValue;
          }
      
          return -1;
      }
      

      我不得不说,这个 Head 属性看起来有点可疑 - 它可能应该属于不同的类。

      【讨论】:

      • 在 size=1 的情况下,头节点不会被移除,对吧?
      • @Fildor 是的,这里的问题是这个奇怪的Head 属性。我们无法真正处理它,因为我们不知道它是什么。所以Head 不会被改变。但我会添加一个示例,说明如果需要该怎么做。
      • 编辑后:更好但仍然没有删除 Head。我怀疑这是第一个节点列表中的参考,但你是对的,OP 应该让我们知道。稍后我会添加一张支票:if( curNode == Head) Head = null;
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-03
      • 1970-01-01
      • 2015-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多