数据结构—Stack堆栈

堆栈(Stack)代表了一个后进先出的对象集合。当需要对各项进行后进先出的访问时,则使用堆栈。当您在列表中添加一项,称为推入元素,当从列表中移除一项时,称为弹出元素。

Stack<T> 

属性 

Count:获取 Stack 中包含的元素个数。

方法描述
void Clear();移除所有的元素
bool Contains( object obj );判断某个元素是否存在
object Peek();返回顶部对象,但不移除它
object Pop();移除并返回顶部对象
void Push( object obj );向顶部添加一个对象
object[] ToArray();复制到一个新的数组中

C#Stack底层原理 

构造函数

         public Stack() {
            _array = new Object[_defaultCapacity];
            _size = 0;
            _version = 0;
        }
    
        // Create a stack with a specific initial capacity.  The initial capacity
        // must be a non-negative number.

        public Stack(int initialCapacity) {
            if (initialCapacity < 0)
                throw new ArgumentOutOfRangeException("initialCapacity", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
            Contract.EndContractBlock();
            if (initialCapacity < _defaultCapacity)
                initialCapacity = _defaultCapacity;  // Simplify doubling logic in Push.
            _array = new Object[initialCapacity];
            _size = 0;
            _version = 0;
        }

创建Stack构造函数时,不添加容量。默认会把容量设置为10.

 

1、Clear()函数

遗憾的是,我搜索了Array.Clear到底是通过什么方式去清楚这些元素。但是没有搜到。微软的文档里没有写。如果有知道的朋友请留言。java的Array.Clear说是通过for循环将对应元素赋值为null

2、bool Contains( object obj );函数

 通过while遍历的形式来找到元素,时间复杂度O(n)。从这段代码我们可以看出Stack是允许插入null值的,翻回到前面的Push(),我们也可以看到,插入的时候并没有对数据做任何的约束。

3、object Peek(); 返回顶部对象,但不移除它

 4、object Pop();移除并返回顶部对象

        public virtual Object Pop() {
            if (_size == 0)
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyStack"));
            //Contract.Ensures(Count == Contract.OldValue(Count) - 1);
            Contract.EndContractBlock();
            _version++;
            Object obj = _array[--_size];
            _array[_size] = null;     // Free memory quicker.
            return obj;
        }

 Peek和Pop的差别在于,Peek只是返回栈顶,Pop是返回栈顶元素的同时并将其删除,所以Peek实质并没有对数据进行更改,不会增加版本号,可以在foreach中使用,而Pop对数据做出了修改,会导致_Version(版本号)+1。_version用来记录版本号(用来在foreach的时候进行判断,任何对栈的更改都会使版本号+1,如果循环中版本号有变化,会抛出异常)。

5、void Push( object obj );向顶部添加一个对象

        public virtual void Push(Object obj) {
            //Contract.Ensures(Count == Contract.OldValue(Count) + 1);
            if (_size == _array.Length) {
                Object[] newArray = new Object[2*_array.Length];
                Array.Copy(_array, 0, newArray, 0, _size);
                _array = newArray;
            }
            _array[_size++] = obj;
            _version++;
        }

当栈的容量已经满了时,创建一个新的数组容器newArray。newArray的容量时初始容量的两倍。将_array中的数据复制给newArray。最后将newArray当作栈的数组容量,_array=newArray;接着讲值放置在数组的末尾,版本号+1(因为栈的数据改变了)。

6、object[] ToArray();

        public virtual Object[] ToArray()
        {
            Contract.Ensures(Contract.Result<Object[]>() != null);
 
            Object[] objArray = new Object[_size];
            int i = 0;
            while(i < _size) {
                objArray[i] = _array[_size-i-1];
                i++;
            }
            return objArray;
        }

遍历所有的元素,进行到新建的数组中,唯一注意的一点是,得到的数组和Stack中的数组顺序是相反的,也就是说栈顶的元素放在了返回的数组的头部

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值