对于栈来说,Push和Pop均是在栈顶完成的,因此很容维护最大值,并且他的时间复杂度是O(1),基本实现以下所示: 算法
1.栈类: 数据结构
public class MyStack { private int _capacity; private int[] _stackItems; private int _maxStackItemIndex; private int _stackTop; private int[] _link2NextMaxitem; public MyStack(int capacity) { _capacity = capacity; _stackTop = -1; _maxStackItemIndex = -1; _link2NextMaxitem = new int[_capacity]; _stackItems = new int[_capacity]; } public void Push(int item) {//压栈 _stackTop++; if (_stackTop >= _capacity) { return false;//越界了 } else { _stackItems[_stackTop] = item; //维护列表,经典, 不管堆栈如何变化_link2NextMaxItem[..._link2NextMaxItem[_link2NextMaxItem[_maxStackItemIndex]]]如此环环相扣的数据保存模式保证了“当时”注意这里是“当时的”第二大数的索引老是能够经过当前的_link2NextMaxItem[_maxStackItemIndex]来得到(同时发生的事情是最大的项被弹出,也就是pop函数里面发生的事情,第二大数成了最大的了),_stackItems[_maxStackItemIndex]则是一直保存着最大项, if (item > Max()) { _link2NextMaxitem[_stackTop] = _maxStackItemIndex;//如下两句顺序不能变,思考一下童鞋 _maxStackItemIndex = _stackTop; } else _link2NextMaxitem[_stackTop] = -1; } } public int Pop() {//弹出元素 int rt = 0; if (_stackTop < 0) throw new Exception("Queue is null"); rt = _stackItems[_stackTop]; //维护列表 if (_stackTop == _maxStackItemIndex) { _maxStackItemIndex = _link2NextMaxitem[_stackTop]; } _stackTop--; return rt; } public int Max() //取最大 { if (_maxStackItemIndex >= 0) return _stackItems[_maxStackItemIndex]; else return -1; } public bool IsEmpty() { return _stackTop == -1; } }
联系上面思想,用两堆栈实现一个队列:队列入队的实现:利用栈B入栈全部元素;队列出队的实现:将栈B中的元素放入栈A,对栈A进行出栈操做正好知足队列元素的出队顺序要求 数据结构和算法
2.队列类(使用了1中定义的堆栈类做为队列的底层数据结构来实现),按照流程画个图就明白了: 函数
/// 队列类 public class MyQueue { //利用堆栈与队列的类似性,用两个堆栈来实现队列 private MyStack _stacka; private MyStack _stackb; public MyQueue(int capacity) { _stacka = new MyStack(capacity); _stackb = new MyStack(capacity); } public void Enqueue(int item) { _stackb.Push(item); } public int Dequeue() { if (_stacka.IsEmpty()) { while (!_stackb.IsEmpty()) _stacka.Push(_stackb.Pop()); } return _stacka.Pop(); } public int Max() { return Math.Max(_stacka.Max(), _stackb.Max()); } }