【问题标题】:How exactly is LinkedList<T> and LinkedListNode<T> implemented in C#? And how exactly does LinkedList<T>.Remove(LinkedListNode<T>) work?LinkedList<T> 和 LinkedListNode<T> 究竟是如何在 C# 中实现的? LinkedList<T>.Remove(LinkedListNode<T>) 究竟是如何工作的?
【发布时间】:2020-10-13 06:18:40
【问题描述】:

我在网上研究了内置的 LinkedList 是 C# 中的双链表。我还研究了 LinkedList.Remove(LinkedListNode) 方法。但我仍然找不到我的问题的答案。 以下是代码sn-p:

    public string DequeueCat()
    {
        LinkedListNode<string> temp = animals.First;
        while (temp != null && temp.Value.Contains("Cat") == false)
        {
            temp = temp.Next;
        }
        if (temp!=null && temp.Value.Contains("Cat"))
        {
            animals.Remove(temp);
            return temp.Value;
        }
        else
        {
            Console.WriteLine("No more Cats available");
            return null;
        }
    }

变量animals 的类型为LinkedList&lt;string&gt;。 当我们用animals.First 实例化一个新的LinkedListNode&lt;string&gt; 时究竟会发生什么?如LinkedListNode&lt;string&gt; temp = animals.First;。 是否发生深度复制,并且原始 LinkedList(由animals.First 指向)被复制到堆上新位置的temp? 此外,当我们编写animals.Remove(temp) 时,temp LinkListNode 被销毁。并且,从animalsLinkedList 中删除相应的值。

下面是执行animals.Remove(temp)之前的监视窗口-

而且,下面是执行animals.Remove(temp) 之后的监视窗口 -

我的问题是,为什么在执行animals.Remove(temp) 之后temp 被破坏了?此外,如果 temp 已在堆上的单独位置创建(与原始 LinkedList 相比),那么我们如何知道从原始删除 tempanimals LinkedList 将从中删除相应的项目 animalsLinkedList?

以下是整个代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AnimalShelter
{
    class AnimalsShelter
    {
        //This class will have the following functions: 
        //Enqueue, DequeueAny, DeQueueDog, DeQueueCat
        //Implement queue using C# inbuilt linked list.
        LinkedList<string> animals = new LinkedList<string>();
        public void Enqueue(string animal)
        {
            animals.AddLast(animal);
        }

        public string DequeueAny()
        {
            LinkedListNode<string> firstAnimal = animals.First;
            if (firstAnimal != null)
            {
                animals.RemoveFirst();
                return firstAnimal.Value;
            }
            else
            {
                Console.WriteLine("No more animanls left in queue.");
                return null;
            }
        }

        public string DequeueDog()
        {
            LinkedListNode<string> temp = animals.First;
            while(temp!=null && temp.Value.Contains("Dog")==false)
            {
                temp = temp.Next;
            }
            if(temp!=null && temp.Value.Contains("Dog"))
            {
                animals.Remove(temp);
                return temp.Value;
            }
            else
            {
                Console.WriteLine("No more Dogs available");
                return null;
            }
        }

        public string DequeueCat()
        {
            LinkedListNode<string> temp = animals.First;
            while (temp != null && temp.Value.Contains("Cat") == false)
            {
                temp = temp.Next;
            }
            if (temp!=null && temp.Value.Contains("Cat"))
            {
                animals.Remove(temp);
                return temp.Value;
            }
            else
            {
                Console.WriteLine("No more Cats available");
                return null;
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            AnimalsShelter shelter = new AnimalsShelter();
            shelter.Enqueue("Dog1");
            shelter.Enqueue("Dog2");
            shelter.Enqueue("Cat1");
            shelter.Enqueue("Dog3");
            shelter.Enqueue("Cat2");
            shelter.Enqueue("Cat3");
            Console.WriteLine(shelter.DequeueCat());
            Console.WriteLine(shelter.DequeueAny());
            Console.WriteLine(shelter.DequeueDog());
            Console.WriteLine(shelter.DequeueCat());
            Console.WriteLine(shelter.DequeueAny());
            Console.WriteLine(shelter.DequeueAny());
        }
    }
}

对此的任何说明都非常感谢。谢谢!

【问题讨论】:

  • @SeanReid,感谢您的指点!所以,当我们说LinkedListNode&lt;string&gt; temp = animals.First;。 tempanimals.First 都在堆栈上,它们指向堆上相同的 LinkedListNode。正确的?此外,animals 变量位于堆栈上,并指向堆上的LinkedList。当我们说animals.Remove(temp)时,temp指向的LinkedListNodeanimals中删除。正确的?此外,temp 变量和 animals 变量都在 Stack 上,它们分别指向堆上的 LinkedListNodeLinkedList。对吗?

标签: c# doubly-linked-list deep-copy


【解决方案1】:

变量animals的类型是LinkedList&lt;string&gt;。究竟是什么 当我们实例化一个新的LinkedListNode&lt;string&gt; 时会发生 animals.First?如LinkedListNode&lt;string&gt; temp = animals.First;。 是否发生深拷贝

没有。你所做的只是复制一个参考LinkedListNode&lt;string&gt; temp = animals.First;

另外,当我们写animals.Remove(temp) 时,临时LinkListNode 是 销毁。

没有。它没有被摧毁,但它的联系正在被移除。它仍然是相同的参考。

我的问题是,为什么 temp 被破坏,执行后 Animals.Remove(temp)?

没有。再一次,它没有被摧毁。但是它的链接正在被删除。

此外,如果 temp 已在堆上的单独位置创建

没有。它尚未在堆上的单独位置创建,您所做的只是复制引用。

那么我们怎么知道从原始动物中移除温度 LinkedList 将从动物中删除相应的项目 链表

我们知道,因为它是同一个对象/同一个引用。

这是Remove 的近似代码。如您所见,没有魔法:

internal void InternalRemoveNode(LinkedListNode<T> node) 
{

     ...

     if ( node.next == node)
            head  = null;      
     else 
     {
         node.next.prev = node.prev;
         node.prev.next = node.next;
         if ( head == node) 
             head = node.next;
     }
     node.Invalidate();  
     count--;
     version++;          
}

进一步阅读

Reference types (C# Reference)

C#中有两种类型:引用类型和值类型。 引用类型的变量存储对其数据(对象)的引用, 而值类型的变量则直接包含它们的数据。和 引用类型,两个变量可以引用同一个对象; 因此,对一个变量的操作会影响引用的对象 由另一个变量。对于值类型,每个变量都有自己的 数据的副本,并且不可能对一个进行操作 影响另一个的变量(除了 in、ref 和 out 的情况 参数变量;请参阅 in、ref 和 out 参数修饰符)。

【讨论】:

  • 感谢您的回答!所以,当我们说LinkedListNode&lt;string&gt; temp = animals.First;tempanimals.First 都在堆栈上,它们指向同一个 LinkedListNode 在堆上。正确的?此外,animals 变量位于堆栈上,并指向堆上的LinkedList。当我们说animals.Remove(temp)时,temp指向的LinkedListNodeanimals中删除。正确的?同样,temp 变量和 animals 变量都在 Stack 上,它们分别指向堆上的 LinkedListNodeLinkedList。对吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 1970-01-01
  • 2011-04-04
  • 2011-05-15
相关资源
最近更新 更多