栈中二三事
在平时唠嗑的时候,总是会听到有大神说,线程栈,函数栈,值类型是存在栈上的等等,好多关于栈的词,大家对这些有兴趣的,且听我慢慢道来。
(一)栈的定义
说起栈,感觉第一个反应就是明修栈道,暗度陈仓...。有一点数据结构的基础同学都知道栈就是先进后出的线性表,其实栈在我们生活中,就像类似洗盘子,先洗的盘子,一个个堆叠起来,拿的时候,从上面第一个开始拿,这就是典型的栈的结构:“后进者,先出,先进者,后出”。
(二)为什么会有栈这种数据结构呢
很多人可能会有这样的疑问,栈,这种先进后出的特点,我用数组,链表也可以实现呀,为啥要有栈的(感觉在编程的世界里面,很多的事情都是类似这样的,C#里面的委托一样,先给一个委托delegate关键字,然后再给一个Func,Action)。我觉得大概是这样的:很多时候,也许你用一个delegate关键字,可能是无所不能,很自由,太多的自由就会导致很难统一。数组和链表也是类似的,很自由,可以随意的两端的插入和删除数据,而栈呢,是等于对特定的场景进行抽象。这可能也是我们编程中很少用到栈的原因把。
(三) 栈的实现
固定大小的栈的复杂度分析,下面是固定大小的栈的实现。这种结构的入栈和出栈的时间复杂度都是O(1)。空间复杂度也是O(1)。特别提醒:空间复杂度是除了原来本身需要的空间之外所需要占用的空间
public class ArrayStack<T> { private int _currentIndex; private T[] _item; public int Count { get; set; } public ArrayStack(int n) { _item = new T[n]; this.Count = n; _currentIndex = 0; } public void Push(T item) { _item[_currentIndex] = item; _currentIndex++; this.Count++; } public T Pop() { if (_currentIndex == 0) { return default(T); } var item = _item[_currentIndex - 1]; _currentIndex--; _item[_currentIndex] = default(T); this.Count--; return item; } }
可以动态调整大小的栈
public class ResizeStack<T> { // private int _defaultSiez = 4; private T[] _item; private int _currentIndex; /// <summary> /// 不指定大小 /// </summary> public ResizeStack() { _item = new T[_defaultSiez]; _currentIndex = 0; } /// <summary> /// 指定大小 /// </summary> /// <param name="n"></param> public ResizeStack(int n) { _item = new T[n]; _currentIndex = 0; } public void Push(T t) { if (_currentIndex >= this._item.Length / 2) { var arr = new T[this._item.Length * 2]; _item.CopyTo(arr,0); _item = arr; } _item[_currentIndex] = t; _currentIndex++; } public T Pop() { var value = default(T); if (_currentIndex == 0) { return value; } value=_item[_currentIndex - 1]; _item[_currentIndex-1]=default(T); _currentIndex--; return value; } public int Count => this._currentIndex+1; }
链式栈的实现
(四)栈的案例
逆波兰表达式,括号匹配等等
终极目标:世界大同