C# Stack源碼剖析

來源:互聯網
上載者:User

標籤:

原始碼版本為 .NET Framework 4.6.1

本系列持續更新,敬請關注

有投入,有產出。

(註:非基礎性,主要涉及Stack的實現原理)

水平有限,若有不對之處,望指正。

Stack(棧)表示對象的後進先出 (LIFO) 集合。實現了ICollection介面。

概念
定義:限定僅在表尾進行插入或刪除操作的線性表,表尾對應棧頂,表頭對應棧底,不含元素的棧稱為空白棧。
入棧:往棧頂插入一個元素。
出棧:在棧頂刪除一個元素

元素的操作只能在棧頂進行,最後入棧的元素最先出棧,結構圖如下:

進入主題

基本成員

        private T[] _array;     // 用於儲存棧元素的數組        private int _size;           // 棧元素的數量        private const int _defaultCapacity = 4; // 預設初始容量        static T[] _emptyArray = new T[0];  // 空數組,用於賦預設值

建構函式

Stack有三個建構函式,分別為:

(1)全部使用Stack設定的預設值,不推薦使用(原因是動態擴容需要額外的計算與開闢新的記憶體空間,動態擴容應該發生在超出預期容量值範圍的情況下,抑制溢出);

        public Stack() {            _array = _emptyArray;            _size = 0;            _version = 0;        }

(2)使用一個非負的整數設定Stack的一個初始容量,推薦使用(給定一個預期的容量值,若預期值小了,會自動擴容,也不擔心溢出)

        public Stack(int capacity) {            if (capacity < 0)                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_NeedNonNegNumRequired);            _array = new T[capacity];            _size = 0;            _version = 0;        }

(3)使用一個現有的非Null 參考集合進行填充初始化Stack,Stack具有與該集合相同的長度,並且按照集合元素的儲存順序(推薦使用實現了Collection泛型介面的集合,可以獲得一些效能上的提升)。

        public Stack(IEnumerable<T> collection)         {            if (collection==null)                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);            ICollection<T> c = collection as ICollection<T>;            if( c != null) {                //實現了ICollection泛型介面的集合,簡單粗暴,分配空間,數組複製                int count = c.Count;                _array = new T[count];                c.CopyTo(_array, 0);                  _size = count;            }                else {                                _size = 0;                //沒有實現ICollection泛型介面的,預設初始容量為4,空間不夠還需動態擴容                        _array = new T[_defaultCapacity];                       //遍曆元素 執行入棧操作                using(IEnumerator<T> en = collection.GetEnumerator()) {                    while(en.MoveNext()) {                        Push(en.Current);                                                        }                }            }        }

入棧

入棧是Stack最核心的方法之一,將元素從棧頂插入到Stack中。觸發動態擴容的條件若且唯若元素數量等於內部儲存元素的數組長度時,開闢一個新的記憶體空間,原來的2倍,原來的記憶體空間將被GC回收並釋放資源

        public void Push(T item) {            //動態擴容            if (_size == _array.Length) {                T[] newArray = new T[(_array.Length == 0) ? _defaultCapacity : 2*_array.Length];                Array.Copy(_array, 0, newArray, 0, _size);                _array = newArray;            }            //將元素存於棧頂位置            _array[_size++] = item;            _version++;        }

出棧

出棧是Stack最核心的方法之一,擷取位於棧頂的元素,空棧不具備出棧功能(強制使用將會引發異常)。分為兩種:
(1)只擷取棧頂元素,不移除。

        public T Peek() {            if (_size==0)                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyStack);            return _array[_size-1];//擷取棧頂元素        }

(2)擷取棧頂元素並將其移除。

        public T Pop() {            if (_size == 0)                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyStack);            _version++;            T item = _array[--_size];       // 擷取棧頂元素,同時棧頂指標前移一位            _array[_size] = default(T);     // 釋放棧頂的記憶體空間            return item;        }

空間壓縮
如果實際元素數量小於當前容量的 90%,將容量設定為 Stack中的實際元素數。推薦在確定不會再有太多的入棧元素時並且初始化容量相比預期值大得多時使用。

        public void TrimExcess() {            int threshold = (int)(((double)_array.Length) * 0.9);                         if( _size < threshold ) {                T[] newarray = new T[_size];                Array.Copy(_array, 0, newarray, 0, _size);                    _array = newarray;                _version++;            }        }    

遍曆
Stack實現了IEnumerable泛型介面的GetEnumerator(),返回一個結構體:

     public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator{            private Stack<T> _stack;    //遍曆的當前棧            private int _index;        // 遍曆標識            private int _version;            private T currentElement;  //當前棧元素            //初始化方法            internal Enumerator(Stack<T> stack) {                _stack = stack;                _version = _stack._version;                _index = -2;                currentElement = default(T);            }             //指標移動,遍曆必須的方法            public bool MoveNext() {                bool retval;                if (_version != _stack._version) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);                if (_index == -2) {  // 開始遍曆                    _index = _stack._size-1;                    retval = ( _index >= 0);                    if (retval)                        currentElement = _stack._array[_index];                    return retval;                }                if (_index == -1) {  // 結束遍曆                    return false;                }                retval = (--_index >= 0);                if (retval)                    currentElement = _stack._array[_index];                else                    currentElement = default(T);                return retval;            }            //擷取遍曆的當前元素,與MoveNext結合使用,即遍曆必須的屬性            public T Current {                get {                    if (_index == -2) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumNotStarted);                    if (_index == -1) ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumEnded);                    return currentElement;                }            }        }

C# Stack源碼剖析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.