Как именно LinkedList и LinkedListNode реализованы в C #? И как именно работает LinkedList.Remove(LinkedListNode)?

#c# #doubly-linked-list #deep-copy

#c# #дважды связанный список #глубокое копирование

Вопрос:

Я исследовал онлайн, что встроенный LinkedList является двусвязным списком в C #. Я также исследовал метод LinkedList.Remove(LinkedListNode). Но я все еще не мог найти ответ на свой вопрос. Ниже приведен фрагмент кода:

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

Переменная animals имеет тип LinkedList<string> .
Что именно происходит, когда мы создаем новый LinkedListNode<string> экземпляр с animals.First помощью ? Например LinkedListNode<string> temp = animals.First; .
Происходит ли глубокое копирование и исходный LinkedList (на который указывает animals.First ), копируется temp в новое место в куче?
Кроме того, когда мы пишем animals.Remove(temp) , temp LinkListNode уничтожается. И соответствующее значение удаляется из animals LinkedList .

Ниже приведено окно просмотра перед выполнением animals.Remove(temp) Окно просмотра перед выполнением animals .Удалить (temp)

И ниже приведено окно просмотра ПОСЛЕ выполнения animals.Remove(temp) Окно просмотра ПОСЛЕ выполнения animals .Удалить (temp)

Мой вопрос в том, почему temp после выполнения уничтожается animals.Remove(temp) ? Кроме того, если temp он был создан в отдельном месте в куче (по сравнению с исходным LinkedList), то откуда мы знаем, что удаление temp из исходного animals LinkedList приведет к удалению соответствующего элемента из animals LinkedList?

Ниже приведен весь код:

 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 amp;amp; temp.Value.Contains("Dog")==false)
            {
                temp = temp.Next;
            }
            if(temp!=null amp;amp; 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 amp;amp; temp.Value.Contains("Cat") == false)
            {
                temp = temp.Next;
            }
            if (temp!=null amp;amp; 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());
        }
    }
}
  

Любой свет на это очень ценится. Спасибо!

Комментарии:

1. Помогает ли это: referencesource.microsoft.com/#system/compmod/system /…

2. @SeanReid, спасибо за ваш указатель! Итак, когда мы говорим LinkedListNode<string> temp = animals.First ;. Оба temp и animals.First находятся в стеке, и они указывают на то же LinkedListNode самое в куче. Правильно? Кроме того, animals переменная находится в стеке и указывает LinkedList на в куче. И когда мы говорим animals.Remove(temp) , LinkedListNode указываемый temp удаляется из animals . Правильно? Также и temp переменная, и animals переменная находятся в стеке, и они указывают на LinkedListNode и LinkedList в куче, соответственно. Правильно?

Ответ №1:

Переменная animals имеет тип LinkedList<string> . Что именно происходит, когда мы создаем новый LinkedListNode<string> экземпляр с animals.First помощью ? Например LinkedListNode<string> temp = animals.First; . Происходит ли глубокое копирование

Нет. Все, что вы сделали, это скопировали ссылку LinkedListNode<string> temp = animals.First;

Кроме того, когда мы пишем animals.Remove(temp) , temp LinkListNode уничтожается.

Нет. Он не уничтожается, однако его ссылки удаляются. Это все та же ссылка.

Мой вопрос в том, почему temp уничтожается после выполнения animals .Удалить (temp)?

Нет. Еще раз, он не уничтожается. однако его ссылки удаляются.

Кроме того, если temp был создан в отдельном месте в куче

Нет. Он не был создан в отдельном месте в куче, все, что вы сделали, это скопировали ссылку.

тогда откуда мы знаем, что удаление temp из исходного, animals LinkedList приведет к удалению соответствующего элемента из animals 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  ;          
}
  

Дальнейшее чтение

Ссылочные типы (C # Reference)

В C # есть два вида типов: ссылочные типы и типы значений. Переменные ссылочных типов хранят ссылки на свои данные (объекты), в то время как переменные типов значений непосредственно содержат их данные. С ссылочными типами две переменные могут ссылаться на один и тот же объект; поэтому операции над одной переменной могут влиять на объект, на который ссылается другая переменная. С типами значений каждая переменная имеет свою собственную копию данных, и операции с одной переменной не могут влиять на другую (за исключением случаев переменных параметров in, ref и out; см. Модификатор параметров in, ref и out).

Комментарии:

1. Спасибо за ваш ответ! Итак, когда мы говорим LinkedListNode<string> temp = animals.First; . Оба temp и animals.First находятся в стеке, и они указывают на то же LinkedListNode самое в куче. Правильно? Кроме того, animals переменная находится в стеке и указывает LinkedList на в куче. И когда мы говорим animals.Remove(temp) , LinkedListNode указываемый temp удаляется из animals . Правильно? Также и temp переменная, и animals переменная находятся в стеке, и они указывают на LinkedListNode и LinkedList в куче, соответственно. Правильно?