一、
实现一个栈,要求实现Push(入栈)、Pop(出栈)、Min(返回最小值的操作)的时间复杂度为O(1)。
分析:
思路1
:利用两个栈,第二个栈的栈顶只放当前原生栈的最小值,Pop和Push时两个栈都进行,Min时只有第二个栈返回其栈顶值。
eg1——
以入栈 5 3 6 7 8 0 为例,其入栈、求最小值、出栈的过程如下图:
此思路在本例题下可行,但如果换个例子,要求入栈 5 3 6 3 3 0 的话就会出状况,这个时候,需要进行改进。
改进1
:如果原生栈中的元素不重复时,第二个栈中不出现重复数字;若原生栈中的元素出现重复时,第二个栈中同样引入该重复数字。
Push时第二个栈只压入截至目前的最小值和原生栈中重复的数,Pop时第二个栈只在等于原生栈中值时才出,Min时只有第二个栈返回其栈顶值。
其
入栈、求最小值、出栈的过程如下图:
但这时仍然存在问题,即当原生栈需要压入的数据有大量重复的时候,思路二的方法的效率就会显得很低。这时仍需要进行改进。
改进2
:使用引用计数,对第二个栈中的每个数配一个引用计数,当引用计数为0时再Pop。此方法为最优方法。
实现:
思路1实现:
#include <iostream> #include <stack> using namespace std; template <class T> class MinStack { public: void Push(const T& x) { _st.push(x); if ((_minst.empty()) || (x < _minst.top())) { _minst.push(x); //minst为空时直接压栈,不为空时需要判断是否为当前最小值 } else { _minst.push(_minst.top()); //保持压入最小值 } } void Pop() { _st.pop(); _minst.pop(); } void Min() { /*return _minst.top();*/ cout << "min= " << _minst.top() << endl; } void Print() { while (!_st.empty()) { cout << _st.top() << " "; _st.pop(); } cout << endl; } protected: stack<T> _st; stack<T> _minst; }; int main() { MinStack<int> s; s.Push(3); s.Push(2); s.Push(6); s.Push(5); s.Push(1); s.Push(7); /*s.Min(); s.Print();*/ s.Pop(); s.Pop(); s.Min(); s.Print(); system("pause"); return 0; }
改进1实现(只需更改Push和Pop):
void Push(const T& x) { _st.push(x); if ((_minst.empty()) || (x <= _minst.top())) { _minst.push(x); //minst为空时直接压栈,不为空时需要判断是否为最小值或重复值 } } void Pop() { if (_st.top() == _minst.top()) { _minst.pop(); } _st.pop(); }
改进2的实现:
template <class T> class MinStack { public: struct ValueRef //定义一个内部类作第二个栈 { T _value; size_t _ref; //计数 ValueRef() //构造 初始化_ref :_ref(0) {} }; protected: stack<T> _st; stack<ValueRef> _minst; };
添加内部类,其他运算据此进行。
二、使用两个栈实现一个队列。
分析:
有两个栈s1和s2,s1负责入队,压栈即可。出队时,若s2为空,将s1中元素导入s2中,若s2不为空,由s2出栈来完成出队。
实现:
#include <iostream> #include <stack> using namespace std; template <typename T> class CQueue { public: CQueue(void) {} ~CQueue(void) {} void appendTail(const T& node); T deleteHead(); private: stack<T> stack1; stack<T> stack2; }; template<class T> void CQueue<T>::appendTail(const T& node)//在队列尾部添加数据 { stack1.push(node); } template<class T> T CQueue<T>::deleteHead() { T tmp = 0; if (stack2.empty()) //若栈2为空 { while (!stack1.empty()) { tmp = stack1.top(); stack2.push(tmp); stack1.pop(); } } tmp = stack2.top(); stack2.pop(); return tmp; } void Test() { CQueue<int> q1; q1.appendTail(1); q1.appendTail(2); q1.appendTail(3); q1.appendTail(4); q1.deleteHead(); q1.appendTail(5); q1.appendTail(6); q1.appendTail(7); } int main() { Test(); system("pause"); return 0; }
三、
使用两个队列实现一个栈
分析:
进栈:把元素push进非空的队列,如果两者都是空的,则随意。
出栈:把非空队列里面的前n-1个元素push到空队列里面,再把最后一个元素拿出来即可。
循环以上步骤,即可得到实现目的。
实现:
#include "queue" #include "iostream" using namespace std; template <typename T> class Stack { public: Stack() { count = 0; } ~Stack() {} void push(const T & data) { if (!q2.empty()) { q2.push(data); } else { q1.push(data); } count++; } T pop() { T temp; if (!q1.empty()) { for (int i = 0; i < count - 1; ++i) { q2.push(q1.front()); q1.pop(); } temp = q1.front(); q1.pop(); count--; return temp; } else if (!q2.empty()) { for (int i = 0; i < count - 1; ++i) { q1.push(q2.front()); q2.pop(); } temp = q2.front(); q2.pop(); count--; return temp; } } T top() { T temp; if (!q1.empty()) { for (int i = 0; i < count - 1; ++i) { q2.push(q1.front()); q1.pop(); } temp = q1.front(); q2.push(temp); q1.pop(); return temp; } else if (!q2.empty()) { for (int i = 0; i < count - 1; ++i) { q1.push(q2.front()); q2.pop(); } temp = q2.front(); q1.push(temp); q2.pop(); return temp; } } int size() const { return count; } bool empty() { return count == 0; } private: queue<T> q1; queue<T> q2; int count; }; template <typename T> //注意非模板类的成员函数的模板姿势 int print(Stack<T> s) { while (!s.empty()) { cout << s.pop() << " "; } cout << endl; }