.NET架構-雙向鏈表(LinkedList)程式碼分析

來源:互聯網
上載者:User


.NET架構中的LinkList,實現的是雙向鏈表,總結下它的實現源碼。

先看下LinkedList提供的公有屬性和方法的導圖:



1 LinkedList實現的介面:

public class LinkedList<T> : ICollection<T>, ICollection, IReadOnlyCollection<T>, ISerializable, IDeserializationCallback

2 LinkedList的全域變數包括,

head是封裝的類內前端節點

        // 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; }}

3 建構函式:

        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的存在性,裡面調用Find方法,

        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); //雙向鏈表,再次遍曆到頭結點時            }        }
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.