. NET Framework of the linklist, the realization of a doubly linked list, summed up its implementation of the source code.
Let's take a look at the map of the public properties and methods provided by LinkedList:
1 interfaces implemented by LinkedList:
public class linkedlist<t>: Icollection<t>, ICollection, Ireadonlycollection<t>, ISerializable, Ideserializationcallback
The global variables of the 2 linkedlist include,
Head is the encapsulated head node in the class;
This linkedlist is a doubly-linked circular list. Internal linkedlistnode<t> head; internal int count; internal int version; Private object _syncroot; A temporary variable which we need during deserialization. Private SerializationInfo _siinfo; Names for serialization Private Const string versionname = "Version"; Private Const string countname = "Count"; Private Const string valuesname = "Data";
The data structure for each of the encapsulated nodes is:
public sealed class linkedlistnode<t>{public LinkedListNode (T value); Gets the LinkedList public linkedlist<t> List {get linkedlistnode belongs to; Public linkedlistnode<t> Next {get;} Public linkedlistnode<t> Previous {get;} Gets the value contained in the node. Public T Value {get; set;}}
3 Constructors:
Public LinkedList ()//default constructor { }//Public LinkedList with Parameters (ienumerable<t> collection) { if (collection = = null) { throw new ArgumentNullException (Nameof (collection)); } foreach (T item in collection) { addlast (item); } }
When constructing the IEnumerable type of collection, the AddLast (T) method is used, and it has an overload with the following working details:
Public linkedlistnode<t> addlast (T value) { linkedlistnode<t> result = new Linkedlistnode<t > (this, value); if (head = = null) { internalinsertnodetoemptylist (result); } else { Internalinsertnodebefore (head, result); } return result; } public void AddLast (linkedlistnode<t> node) { Validatenewnode (node); if (head = = null) { internalinsertnodetoemptylist (node); } else { Internalinsertnodebefore (Head, node); } Node.list = this; Combine LinkedListNode to see }
The 2 methods above, the semantics is to insert a node,
Insert a new node into the empty list, internalinsertnodetoemptylist
Inserts a new node into the list that is not empty, internalinsertnodebefore, and gives the node before which the NewNode is inserted, and also determines whether the newly inserted node is a valid new node.
internal void Validatenewnode (linkedlistnode<t> node) { if (node = = null) { throw new ArgumentNullException (nameof (node)); } if (node.list! = null) { throw new InvalidOperationException (SR. linkedlistnodeisattached); } }
At the same time, we also determine whether a node is a valid node:
internal void Validatenode (linkedlistnode<t> node) { if (node = = null) { throw new ArgumentNullException (nameof (node)); } if (node.list! = this) { throw new InvalidOperationException (SR. Externallinkedlistnode); } }
This is an important internal method of the doubly linked list,
Implementation details of the internalinsertnodetoemptylist:
private void Internalinsertnodetoemptylist (linkedlistnode<t> newNode) { Debug.Assert (head = = NULL && count = = 0, "LinkedList must was empty when this method is called!"); Newnode.next = NewNode; Newnode.prev = NewNode; head = NewNode; version++; count++; }
Implementation details of the Internalinsertnodebefore:
private void Internalinsertnodebefore (linkedlistnode<t> node, linkedlistnode<t> newNode) { newnode.next = node; Newnode.prev = Node.prev; Node.prev.next = NewNode; Node.prev = NewNode; version++; count++; }
4 linked lists are naturally inseparable from the public method of inserting a node,
Public linkedlistnode<t> Addafter (linkedlistnode<t> node, T value) {Validatenode (no DE); linkedlistnode<t> result = new Linkedlistnode<t> (node.list, value); Internalinsertnodebefore (node.next, result); return result; } public void Addafter (linkedlistnode<t> node, linkedlistnode<t> newNode) {Validaten Ode (node); Validatenewnode (NewNode); Internalinsertnodebefore (Node.next, NewNode); Newnode.list = this; } public linkedlistnode<t> Addbefore (linkedlistnode<t> node, T value) {Validatenode ( node); linkedlistnode<t> result = new Linkedlistnode<t> (node.list, value); Internalinsertnodebefore (node, result); if (node = = head) {head = result; } return result; } public void Addbefore (Linkedlistnode<t> node, linkedlistnode<t> newNode) {validatenode (node); Validatenewnode (NewNode); Internalinsertnodebefore (node, newNode); Newnode.list = this; if (node = = head) {head = NewNode; }} public linkedlistnode<t> AddFirst (T value) {linkedlistnode<t> result = NE W linkedlistnode<t> (this, value); if (head = = null) {internalinsertnodetoemptylist (result); } else {Internalinsertnodebefore (head, result); Head = result; } return result; } public void AddFirst (linkedlistnode<t> node) {Validatenewnode (node); if (head = = null) {internalinsertnodetoemptylist (node); } else {inTernalinsertnodebefore (head, node); Head = node; } node.list = this; Public linkedlistnode<t> addlast (T value) {linkedlistnode<t> result = new Linkedli Stnode<t> (this, value); if (head = = null) {internalinsertnodetoemptylist (result); } else {Internalinsertnodebefore (head, result); } return result; } public void AddLast (linkedlistnode<t> node) {Validatenewnode (node); if (head = = null) {internalinsertnodetoemptylist (node); } else {Internalinsertnodebefore (Head, node); } node.list = this; }
5 Look again, clear the list of all nodes, here is set all nodes are not pointing to the memory heap, and so on GC recycle,
public void Clear () { linkedlistnode<t>-current = head; while (current! = null) { linkedlistnode<t> temp = current; Current = current. Next; Use next the instead of "next", otherwise it'll loop forever temp. Invalidate (); } head = NULL; Count = 0; version++; }
6 corresponds only to the removal of a node of some of the column interface, and add a similar, no longer repeat,
Clear inside calls the invalidate (), the implementation is very simple:
internal void Invalidate () { list = null; next = null; prev = null; }
7 Determine the existence of a node value as value, which calls the Find method,
public bool Contains (T value) { return Find (value)! = null; }
The Find method implements the details, similar APIs have findlast, because it is a doubly linked list, so from the end of the chain to go through the list,
Public linkedlistnode<t> Find (T value) {linkedlistnode<t> node = head; Call the default equality comparer equalitycomparer<t> C = equalitycomparer<t>. Default; if (node! = NULL)//The linked list is null {if (value! = null) { do {if (C.equals (Node.item, value))//equa LS: The item of a node is equal to value {return node; } node = Node.next; } while (node! = head); } else {do { if (Node.item = = null) { return node; } node = Node.next; } while (node! = head); }} return null; The linked list is NULL, directly returning NULL}
8 Look at a copy of the data to the array implementation:
public void CopyTo (t[] array, int index) {if (array = = NULL) { throw new ArgumentNullException (nameof (array)); } if (Index < 0) {throw new ArgumentOutOfRangeException (n Ameof (index), index, SR. Argumentoutofrange_neednonnegnum); } if (Index > array. Length) {throw new ArgumentOutOfRangeException (nameof (index), index, SR.) Argumentoutofrange_biggerthancollection); } if (array. Length-index < Count) {throw new ArgumentException (SR.) Arg_insufficientspace); } linkedlistnode<t> node = head; if (node! = null) {do {array[index++] = Node.item; node = Node.next; } while (node! = head); Doubly linked list, when traversing the head node again}}