Assembly: System (in system.dll)
<SerializableAttribute> _ <ComVisibleAttribute(False)> _ Public Class LinkedList(Of T) Implements ICollection(Of T), IEnumerable(Of T), _ ICollection, IEnumerable, ISerializable, IDeserializationCallback
Dim instance As LinkedList(Of T)
[SerializableAttribute] [ComVisibleAttribute(false)] public class LinkedList<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable, ISerializable, IDeserializationCallback
[SerializableAttribute] [ComVisibleAttribute(false)] generic<typename T> public ref class LinkedList : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable, ISerializable, IDeserializationCallback
J# supports the use of generic types and methods, but not the declaration of new ones.
JScript does not support generic types and methods.
Not applicable.
Type Parameters
- T
Specifies the element type of the linked list.
LinkedList is a general-purpose linked list. It supports enumerators and implements the ICollection interface, consistent with other collection classes in the .NET Framework.
LinkedList provides separate nodes of type LinkedListNode, so insertion and removal are O(1) operations.
You can remove nodes and reinsert them, either in the same list or in another list, which results in no additional objects allocated on the heap. Because the list also maintains an internal count, getting the Count property is an O(1) operation.
Each node in a LinkedList object is of the type LinkedListNode. Because the LinkedList is doubly linked, each node points forward to the Next node and backward to the Previous node.
Lists that contain reference types perform better when a node and its value are created at the same time. LinkedList accepts a null reference (Nothing in Visual Basic) as a valid Value property for reference types and allows duplicate values.
If the LinkedList is empty, the First and Last properties contain a null reference (Nothing in Visual Basic).
The LinkedList class does not support chaining, splitting, cycles, or other features that can leave the list in an inconsistent state. The list remains consistent on a single thread. The only multithreaded scenario supported by LinkedList is multithreaded read operations.
The following code example demonstrates many features of the LinkedList class.
Imports System Imports System.Text Imports System.Collections.Generic Public Class Example Public Shared Sub Main() ' Create the link list. Dim words() As String = {"the", "fox", _ "jumped", "over", "the", "dog"} Dim sentence As New LinkedList(Of String)(words) Display(sentence, "The linked list values:") ' Add the word 'today' to the beginning of the linked list. sentence.AddFirst("today") Display(sentence, "Test 1: Add 'today' to beginning of the list:") ' Move the first node to be the last node. Dim mark1 As LinkedListNode(Of String) = sentence.First sentence.RemoveFirst() sentence.AddLast(mark1) Display(sentence, "Test 2: Move first node to be last node:") ' Change the last node be 'yesterday'. sentence.RemoveLast() sentence.AddLast("yesterday") Display(sentence, "Test 3: Change the last node to 'yesterday':") ' Move the last node to be the first node. mark1 = sentence.Last sentence.RemoveLast() sentence.AddFirst(mark1) Display(sentence, "Test 4: Move last node to be first node:") ' Indicate, by using parentheisis, the last occurence of 'the'. sentence.RemoveFirst() Dim current As LinkedListNode(Of String) = sentence.FindLast("the") IndicateNode(current, "Test 5: Indicate last occurence of 'the':") ' Add 'lazy' and 'old' after 'the' (the LinkedListNode named current). sentence.AddAfter(current, "old") sentence.AddAfter(current, "lazy") IndicateNode(current, "Test 6: Add 'lazy' and 'old' after 'the':") ' Indicate 'fox' node. current = sentence.Find("fox") IndicateNode(current, "Test 7: Indicate the 'fox' node:") ' Add 'quick' and 'brown' before 'fox': sentence.AddBefore(current, "quick") sentence.AddBefore(current, "brown") IndicateNode(current, "Test 8: Add 'quick' and 'brown' before 'fox':") ' Keep a reference to the current node, 'fox', ' and to the previous node in the list. Indicate the 'dog' node. mark1 = current Dim mark2 As LinkedListNode(Of String) = current.Previous current = sentence.Find("dog") IndicateNode(current, "Test 9: Indicate the 'dog' node:") ' The AddBefore method throws an InvalidOperationException ' if you try to add a node that already belongs to a list. Console.WriteLine("Test 10: Throw exception by adding node (fox) already in the list:") Try sentence.AddBefore(current, mark1) Catch ex As InvalidOperationException Console.WriteLine("Exception message: {0}", ex.Message) End Try Console.WriteLine() ' Remove the node referred to by mark1, and then add it ' before the node referred to by current. ' Indicate the node referred to by current. sentence.Remove(mark1) sentence.AddBefore(current, mark1) IndicateNode(current, "Test 11: Move a referenced node (fox) before the current node (dog):") ' Remove the node referred to by current. sentence.Remove(current) IndicateNode(current, "Test 12: Remove current node (dog) and attempt to indicate it:") ' Add the node after the node referred to by mark2. sentence.AddAfter(mark2, current) IndicateNode(current, "Test 13: Add node removed in test 11 after a referenced node (brown):") ' The Remove method finds and removes the ' first node that that has the specified value. sentence.Remove("old") Display(sentence, "Test 14: Remove node that has the value 'old':") ' When the linked list is cast to ICollection(Of String), ' the Add method adds a node to the end of the list. sentence.RemoveLast() Dim icoll As ICollection(Of String) = sentence icoll.Add("rhinoceros") Display(sentence, "Test 15: Remove last node, cast to ICollection, and add 'rhinoceros':") Console.WriteLine("Test 16: Copy the list to an array:") ' Create an array with the same number of ' elements as the inked list. Dim sArray() As String = New String((sentence.Count) - 1) {} sentence.CopyTo(sArray, 0) For Each s As String In sArray Console.WriteLine(s) Next ' Release all the nodes. sentence.Clear() Console.WriteLine() Console.WriteLine("Test 17: Clear linked list. Contains 'jumped' = {0}", sentence.Contains("jumped")) Console.ReadLine() End Sub Private Shared Sub Display(ByVal words As LinkedList(Of String), ByVal test As String) Console.WriteLine(test) For Each word As String In words Console.Write((word + " ")) Next Console.WriteLine() Console.WriteLine() End Sub Private Shared Sub IndicateNode(ByVal node As LinkedListNode(Of String), ByVal test As String) Console.WriteLine(test) If IsNothing(node.List) Then Console.WriteLine("Node '{0}' is not in the list." & vbLf, node.Value) Return End If Dim result As StringBuilder = New StringBuilder(("(" _ + (node.Value + ")"))) Dim nodeP As LinkedListNode(Of String) = node.Previous While (Not (nodeP) Is Nothing) result.Insert(0, (nodeP.Value + " ")) nodeP = nodeP.Previous End While node = node.Next While (Not (node) Is Nothing) result.Append((" " + node.Value)) node = node.Next End While Console.WriteLine(result) Console.WriteLine() End Sub End Class 'This code example produces the following output: ' 'The linked list values: 'the fox jumped over the dog 'Test 1: Add 'today' to beginning of the list: 'today the fox jumped over the dog 'Test 2: Move first node to be last node: 'the fox jumped over the dog today 'Test 3: Change the last node to 'yesterday': 'the fox jumped over the dog yesterday 'Test 4: Move last node to be first node: 'yesterday the fox jumped over the dog 'Test 5: Indicate last occurence of 'the': 'the fox jumped over (the) dog 'Test 6: Add 'lazy' and 'old' after 'the': 'the fox jumped over (the) lazy old dog 'Test 7: Indicate the 'fox' node: 'the (fox) jumped over the lazy old dog 'Test 8: Add 'quick' and 'brown' before 'fox': 'the quick brown (fox) jumped over the lazy old dog 'Test 9: Indicate the 'dog' node: 'the quick brown fox jumped over the lazy old (dog) 'Test 10: Throw exception by adding node (fox) already in the list: 'Exception message: The LinkedList node belongs a LinkedList. 'Test 11: Move a referenced node (fox) before the current node (dog): 'the quick brown jumped over the lazy old fox (dog) 'Test 12: Remove current node (dog) and attempt to indicate it: 'Node 'dog' is not in the list. 'Test 13: Add node removed in test 11 after a referenced node (brown): 'the quick brown (dog) jumped over the lazy old fox 'Test 14: Remove node that has the value 'old': 'the quick brown dog jumped over the lazy fox 'Test 15: Remove last node, cast to ICollection, and add 'rhinoceros': 'the quick brown dog jumped over the lazy rhinoceros 'Test 16: Copy the list to an array: 'the 'quick 'brown 'dog 'jumped 'over 'the 'lazy 'rhinoceros 'Test 17: Clear linked list. Contains 'jumped' = False '
using System; using System.Text; using System.Collections.Generic; public class Example { public static void Main() { // Create the link list. string[] words = { "the", "fox", "jumped", "over", "the", "dog" }; LinkedList<string> sentence = new LinkedList<string>(words); Display(sentence, "The linked list values:"); // Add the word 'today' to the beginning of the linked list. sentence.AddFirst("today"); Display(sentence, "Test 1: Add 'today' to beginning of the list:"); // Move the first node to be the last node. LinkedListNode<string> mark1 = sentence.First; sentence.RemoveFirst(); sentence.AddLast(mark1); Display(sentence, "Test 2: Move first node to be last node:"); // Change the last node be 'yesterday'. sentence.RemoveLast(); sentence.AddLast("yesterday"); Display(sentence, "Test 3: Change the last node to 'yesterday':"); // Move the last node to be the first node. mark1 = sentence.Last; sentence.RemoveLast(); sentence.AddFirst(mark1); Display(sentence, "Test 4: Move last node to be first node:"); // Indicate, by using parentheisis, the last occurence of 'the'. sentence.RemoveFirst(); LinkedListNode<string> current = sentence.FindLast("the"); IndicateNode(current, "Test 5: Indicate last occurence of 'the':"); // Add 'lazy' and 'old' after 'the' (the LinkedListNode named current). sentence.AddAfter(current, "old"); sentence.AddAfter(current, "lazy"); IndicateNode(current, "Test 6: Add 'lazy' and 'old' after 'the':"); // Indicate 'fox' node. current = sentence.Find("fox"); IndicateNode(current, "Test 7: Indicate the 'fox' node:"); // Add 'quick' and 'brown' before 'fox': sentence.AddBefore(current, "quick"); sentence.AddBefore(current, "brown"); IndicateNode(current, "Test 8: Add 'quick' and 'brown' before 'fox':"); // Keep a reference to the current node, 'fox', // and to the previous node in the list. Indicate the 'dog' node. mark1 = current; LinkedListNode<string> mark2 = current.Previous; current = sentence.Find("dog"); IndicateNode(current, "Test 9: Indicate the 'dog' node:"); // The AddBefore method throws an InvalidOperationException // if you try to add a node that already belongs to a list. Console.WriteLine("Test 10: Throw exception by adding node (fox) already in the list:"); try { sentence.AddBefore(current, mark1); } catch (InvalidOperationException ex) { Console.WriteLine("Exception message: {0}", ex.Message); } Console.WriteLine(); // Remove the node referred to by mark1, and then add it // before the node referred to by current. // Indicate the node referred to by current. sentence.Remove(mark1); sentence.AddBefore(current, mark1); IndicateNode(current, "Test 11: Move a referenced node (fox) before the current node (dog):"); // Remove the node referred to by current. sentence.Remove(current); IndicateNode(current, "Test 12: Remove current node (dog) and attempt to indicate it:"); // Add the node after the node referred to by mark2. sentence.AddAfter(mark2, current); IndicateNode(current, "Test 13: Add node removed in test 11 after a referenced node (brown):"); // The Remove method finds and removes the // first node that that has the specified value. sentence.Remove("old"); Display(sentence, "Test 14: Remove node that has the value 'old':"); // When the linked list is cast to ICollection(Of String), // the Add method adds a node to the end of the list. sentence.RemoveLast(); ICollection<string> icoll = sentence; icoll.Add("rhinoceros"); Display(sentence, "Test 15: Remove last node, cast to ICollection, and add 'rhinoceros':"); Console.WriteLine("Test 16: Copy the list to an array:"); // Create an array with the same number of // elements as the inked list. string[] sArray = new string[sentence.Count]; sentence.CopyTo(sArray, 0); foreach (string s in sArray) { Console.WriteLine(s); } // Release all the nodes. sentence.Clear(); Console.WriteLine(); Console.WriteLine("Test 17: Clear linked list. Contains 'jumped' = {0}", sentence.Contains("jumped")); Console.ReadLine(); } private static void Display(LinkedList<string> words, string test) { Console.WriteLine(test); foreach (string word in words) { Console.Write(word + " "); } Console.WriteLine(); Console.WriteLine(); } private static void IndicateNode(LinkedListNode<string> node, string test) { Console.WriteLine(test); if (node.List == null) { Console.WriteLine("Node '{0}' is not in the list.\n", node.Value); return; } StringBuilder result = new StringBuilder("(" + node.Value + ")"); LinkedListNode<string> nodeP = node.Previous; while (nodeP != null) { result.Insert(0, nodeP.Value + " "); nodeP = nodeP.Previous; } node = node.Next; while (node != null) { result.Append(" " + node.Value); node = node.Next; } Console.WriteLine(result); Console.WriteLine(); } } //This code example produces the following output: // //The linked list values: //the fox jumped over the dog //Test 1: Add 'today' to beginning of the list: //today the fox jumped over the dog //Test 2: Move first node to be last node: //the fox jumped over the dog today //Test 3: Change the last node to 'yesterday': //the fox jumped over the dog yesterday //Test 4: Move last node to be first node: //yesterday the fox jumped over the dog //Test 5: Indicate last occurence of 'the': //the fox jumped over (the) dog //Test 6: Add 'lazy' and 'old' after 'the': //the fox jumped over (the) lazy old dog //Test 7: Indicate the 'fox' node: //the (fox) jumped over the lazy old dog //Test 8: Add 'quick' and 'brown' before 'fox': //the quick brown (fox) jumped over the lazy old dog //Test 9: Indicate the 'dog' node: //the quick brown fox jumped over the lazy old (dog) //Test 10: Throw exception by adding node (fox) already in the list: //Exception message: The LinkedList node belongs a LinkedList. //Test 11: Move a referenced node (fox) before the current node (dog): //the quick brown jumped over the lazy old fox (dog) //Test 12: Remove current node (dog) and attempt to indicate it: //Node 'dog' is not in the list. //Test 13: Add node removed in test 11 after a referenced node (brown): //the quick brown (dog) jumped over the lazy old fox //Test 14: Remove node that has the value 'old': //the quick brown dog jumped over the lazy fox //Test 15: Remove last node, cast to ICollection, and add 'rhinoceros': //the quick brown dog jumped over the lazy rhinoceros //Test 16: Copy the list to an array: //the //quick //brown //dog //jumped //over //the //lazy //rhinoceros //Test 17: Clear linked list. Contains 'jumped' = False //
#using <System.dll> using namespace System; using namespace System::Text; using namespace System::Collections::Generic; void Display(LinkedList<String^>^ words) { for each( String^ word in words ) { Console::Write(word + " "); } Console::WriteLine(); }; void DisplayNode(LinkedListNode<String^>^ node) { if (node->List == nullptr) { Console::WriteLine("Node \"{0}\" is not in a list.", node->Value); return; } StringBuilder^ result = gcnew StringBuilder("(" + node->Value + ")"); LinkedListNode<String^>^ nodeP = node->Previous; while (nodeP != nullptr) { result->Insert(0, nodeP->Value + " "); nodeP = nodeP->Previous; } node = node->Next; while (node != nullptr) { result->Append(" " + node->Value); node = node->Next; } Console::WriteLine(result); }; void main() { array<String^>^ words = {"the", "fox", "jumped", "over", "the", "dog"}; LinkedList<String^>^ sentence = gcnew LinkedList<String^>((IEnumerable<String^>^) words); Display(sentence); Console::WriteLine("sentence->Contains(\"jumped\") = {0}", sentence->Contains("jumped")); // Add the word "today" to the beginning of the linked list. // Remove the new node, and add it to the end of the list. sentence->AddFirst("today"); Display(sentence); LinkedListNode<String^>^ mark1 = sentence->First; sentence->RemoveFirst(); sentence->AddLast(mark1); Display(sentence); sentence->RemoveLast(); sentence->AddLast("yesterday"); Display(sentence); mark1 = sentence->Last; sentence->RemoveLast(); sentence->AddFirst(mark1); Display(sentence); sentence->RemoveFirst(); LinkedListNode<String^>^ current = sentence->FindLast("the"); DisplayNode(current); sentence->AddAfter(current, "old"); sentence->AddAfter(current, "lazy"); DisplayNode(current); current = sentence->Find("fox"); DisplayNode(current); sentence->AddBefore(current, "quick"); sentence->AddBefore(current, "brown"); DisplayNode(current); // Keep a reference to the current node, "fox", and to the // previous node in the list. Use the Find method to locate // the node containing the value "dog". Show the position. mark1 = current; LinkedListNode<String^>^ mark2 = current->Previous; current = sentence->Find("dog"); DisplayNode(current); // The AddBefore method throws an InvalidOperationException // if you try to add a node that already belongs to a list. try { sentence->AddBefore(current, mark1); } catch(InvalidOperationException^ ex) { Console::WriteLine("Exception message: {0}", ex->Message); } // Remove the node referred to by mark1, and add it before // the node referred to by current. Show the sentence, // highlighting the position of the node referred to by // current. sentence->Remove(mark1); sentence->AddBefore(current, mark1); DisplayNode(current); // Remove the node referred to by current. If you try to show // its position now, the DisplayNode method prints a message. // Add the node after the node referred to by mark2, and // display the sentence, highlighting current. sentence->Remove(current); DisplayNode(current); sentence->AddAfter(mark2, current); DisplayNode(current); // The Remove method finds and removes the first node that // that has the specified value. sentence->Remove("old"); Display(sentence); // When the linked list is cast to ICollection(Of String), // the Add method adds a node to the end of the list. sentence->RemoveLast(); ICollection<String^>^ icoll = sentence; icoll->Add("rhinoceros"); Display(sentence); // Create an array with the same number of elements as the // linked list. Console::WriteLine("\nCopy the list to an array."); array<String^>^ sArray = gcnew array<String^>(sentence->Count); sentence->CopyTo(sArray, 0); for each( String^ s in sArray ) { Console::WriteLine(s); } // Release all the nodes. sentence->Clear(); } //This code example produces the following output: // //the fox jumped over the dog //sentence->Contains("jumped") = True //today the fox jumped over the dog //the fox jumped over the dog today //the fox jumped over the dog yesterday //yesterday the fox jumped over the dog //the fox jumped over (the) dog //the fox jumped over (the) lazy old dog //the (fox) jumped over the lazy old dog //the quick brown (fox) jumped over the lazy old dog //the quick brown fox jumped over the lazy old (dog) //Exception message: The LinkedList node belongs a LinkedList. //the quick brown jumped over the lazy old fox (dog) //Node "dog" is not in a list. //the quick brown (dog) jumped over the lazy old fox //the quick brown dog jumped over the lazy fox //the quick brown dog jumped over the lazy rhinoceros // //Copy the list to an array. //the //quick //brown //dog //jumped //over //the //lazy //rhinoceros
System.Collections.Generic.LinkedList
This type is not thread safe. If the LinkedList needs to be accessed by multiple threads, you will need to implement their own synchronization mechanism.
A LinkedList can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. In the rare case where an enumeration contends with write accesses, the collection must be locked during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.
Windows 98, Windows Server 2000 SP4, Windows CE, Windows Millennium Edition, Windows Mobile for Pocket PC, Windows Mobile for Smartphone, Windows Server 2003, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP SP2, Windows XP Starter Edition
The Microsoft .NET Framework 3.0 is supported on Windows Vista, Microsoft Windows XP SP2, and Windows Server 2003 SP1..NET Framework
Supported in: 3.0, 2.0.NET Compact Framework
Supported in: 2.0XNA Framework
Supported in: 1.0This one needs a good bit of caution from a perfomance perspective. Actually this is a great example of the kind of tension that you see in a set of libraries like the BCL that is trying to serve a wide-range of customers. We'd like to have ease of use features like being able to get from a list node back to the list because customers request these things. We also like to be able to do internal sanity checks because they are common pitfalls and addressing them goes a long way to helping developer productivity. So sometimes we make choices that are far from the most performant because perf isn't deemed to be the high order bit on developer productivity.
Consider the linked list node:
public sealed class LinkedListNode<T>
{
public LinkedListNode(T value);
public LinkedList<T> List { get; }
public LinkedListNode<T> Next { get; }
public LinkedListNode<T> Previous { get; }
public T Value { get; set; }
}
OK just from that description we can see that the list is doubly linked and each node has a parent pointer to the head of the list. So what's the minimum cost of a node?
Well let's say T is Object we have to have
-obj header
-method table pointer
-parent pointer
-next pointer
-previous pointer
-the Object (also pointer)
total size 24 bytes. Eep!
Now if instead we just threaded a singly linked through the actual class we intend to make a list out of the marginal cost would be only 4 bytes per node. But of course we'd have to be able to modify the class...
So does that mean this list implementation is bad? Hardly, but if you were going to have millions of nodes I'd probably use something else.