.NET框架中的LinkList,實作的是雙向鍊錶,總結下它的實作原始碼。
先看下LinkedList提供的公有屬性與方法的導圖:
1 LinkedList實作的介面:
public class LinkedList<T> : ICollection<T>, ICollection, IReadOnlyCollection<T>, ISerializable, IDeserializationCallback
2 LinkedList的全域變數包括,
# #是封裝的類別內頭節點;
// 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";
封裝的每個節點的資料結構為:
public sealed class LinkedListNode<T> { public LinkedListNode(T value); //获取LinkedListNode所属的LinkedList public LinkedList<T> List { get; } public LinkedListNode<T> Next { get; } public LinkedListNode<T> Previous { get; } //获取节点中包含的值。 public T Value { get; set; } }
:
public LinkedList() //默认的构造函数 { } //带有参数的 public LinkedList(IEnumerable<T> collection) { if (collection == null) { throw new ArgumentNullException(nameof(collection)); } foreach (T item in collection) { AddLast(item); } }
在建構IEnumerable類型的collection時,用到了AddLast(T)方法,它還有一個
重載,工作細節如下:
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; //结合LinkedListNode看 }
以上2個方法,語意是插入某個節點,
分插入新節點到空list中,InternalInsertNodeToEmptyList插入新節點到不為空的list中,InternalInsertNodeBefore,並且給出在哪個節點前插入newNode,還判斷了新插入的節點是不是一個有效的新節點。
internal void ValidateNewNode(LinkedListNode<T> node) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (node.list != null) { throw new InvalidOperationException(SR.LinkedListNodeIsAttached); } }
同時,也給出判斷一個節點是不是有效節點:
internal void ValidateNode(LinkedListNode<T> node) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (node.list != this) { throw new InvalidOperationException(SR.ExternalLinkedListNode); } }
這是雙向鍊錶比較重要的內部方法,
InternalInsertNodeToEmptyList的實作細節:
private void InternalInsertNodeToEmptyList(LinkedListNode<T> newNode) { Debug.Assert(head == null && count == 0, "LinkedList must be empty when this method is called!"); newNode.next = newNode; newNode.prev = newNode; head = newNode; version++; count++; }
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 鍊錶自然離不開插入某個節點的公有方法,
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value) { ValidateNode(node); LinkedListNode<T> result = new LinkedListNode<T>(node.list, value); InternalInsertNodeBefore(node.next, result); return result; } public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode) { ValidateNode(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 = new 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 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; }
5 再看下,清除鍊錶所有節點,此處是設定所有節點不在指向記憶體堆,然後等GC回收, 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 will loop forever
temp.Invalidate();
}
head = null;
count = 0;
version++;
}
6 與只相對應的是移除某個節點的一些列接口,與添加類似,不再贅述,
Clear裡面呼叫了Invalidate(),實作很簡單: internal void Invalidate()
{
list = null;
next = null;
prev = null;
}
7 判斷某個節點值為value的存在性,裡面呼叫
public bool Contains(T value) { return Find(value) != null; }## #Find方法實作細節,類似的###API###還有FindLast,因為是雙向鍊錶,所以從尾部開始遍歷鍊錶即可,###
public LinkedListNode<T> Find(T value) { LinkedListNode<T> node = head; //调用默认相等比较器 EqualityComparer<T> c = EqualityComparer<T>.Default; if (node != null)//链表为null { if (value != null) { do { if (c.Equals(node.item, value)) //Equals:某个节点node的item与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; //链表为null,直接返回null }###8 再看一個複製資料到###陣列###的實作:###
public void CopyTo(T[] array, int index) { if (array == null) { throw new ArgumentNullException(nameof(array)); } if (index < 0) { throw new ArgumentOutOfRangeException(nameof(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); //双向链表,再次遍历到头结点时 } }######
以上是.NET框架-雙向鍊錶(LinkedList)程式碼分析(圖)的詳細內容。更多資訊請關注PHP中文網其他相關文章!