开篇点题,今天做了几道栈和队列的题,
在此,记录分享
1、实现一个栈,要求这个栈实现Push(出栈)、Pop(入栈)、Min(返回最小值的操作的时间复杂度为O(1))
来分析一下,
思路1:我们可以底层用两个栈来实现
先建个类,写个框架,实现3个接口
class MinSt
{
public:
void Push(const int& x)
{...}
void Pop()
{...}
int Min()
{...}
protected:
stack<int> _st;
stack<int> _minst;
};
然后我们再来分析一下如何写,分析一下过程
虽然我们底层是用两个栈实现的,但外面看起来要像一个栈,那么我们这两个栈要保持一致,同进同出
这里进栈出栈时,_st栈不用特殊考虑,但_minst我们是用它记录最小值的所以要特殊考虑
我们可以从上图看到,_minst入栈的要求是比当前栈顶的数小或者等于才能入栈,否则将当前栈顶再入栈
void Push(const int& x)
{
_st.push(x);
if (_minst.size() == 0||x<_minst.top())
{
_minst.push(x);
}
else
{
_minst.push(_minst.top());
}
}
此时我们_minst的栈顶永远是最小值
出栈时,只要考虑不为空即可
void Pop()
{
if (!_st.empty() && !_minst.empty())
{
_st.pop();
_minst.pop();
}
}
返回最小值就Pop出_minst栈顶
int Min()
{
if (!_minst.empty())
{
return _minst.top();
}
}
测试一下
void test1()
{
MinSt s;
s.Push(5);
s.Push(3);
s.Push(6);
s.Push(1);
s.Push(2);
s.Pop();
s.Pop();
cout << s.Min() << endl;
}
这个写法还可以优化,_minst中重复入栈3,我们还可以用其他方法优化,后面再补充
2、用两个栈实现一个队列
我们先来画图分析一下
class TwoStackOneQueue
{
public:
...
private:
stack<int> PushStack;
stack<int> PopStack;
};
先创建两个栈,一个用来入,一个用来出
我们大概先说一下思路
入栈1,2,3
当要Pop时,将1,2,3导入进PopStack,这时的栈顶,就是我们应该要Pop的正确数了
然后我们再入栈时应该入PushStack
首先我们先来实现Push()接口,这个接口我们不用特别考虑什么,想清楚入栈都入PushStack
void Push(const int&x)
{
//入时永远入PushStack栈
PushStack.push(x);
}
然后就是出栈
我们每次出PopStack即可,如果为空了,就将PushStack倒过去,再出就好
下面是全部代码
class TwoStackOneQueue
{
public:
void Push(const int&x)
{
//入时永远入PushStack栈
PushStack.push(x);
}
void Pop()
{
if (PopStack.empty())
{
PutPop();
}
PopStack.pop();
}
int& Front()
{
if (PopStack.empty())
{
PutPop();
}
return PopStack.top();
}
bool Empty()
{
return PushStack.empty() && PopStack.empty();
}
size_t Size()
{
return PushStack.size() + PopStack.size();
}
private:
void PutPop()
{
while (!PushStack.empty())
{
PopStack.push(PushStack.top());
PushStack.pop();
}
}
private:
stack<int> PushStack;
stack<int> PopStack;
};
void test2()
{
TwoStackOneQueue q;
q.Push(1);
q.Push(2);
q.Push(3);
q.Pop();
cout<<q.Front()<<endl;//2
q.Pop();
cout << q.Front() << endl;//3
q.Push(4);
q.Pop();
cout << q.Front() << endl;//4
}
3、用两个队列实现一个栈
入队列1,2,3,4
可是我们现在要出4,所以我们可以将1,2,3全放到另一个队列中去,就可以出4了
我们如数据的时候都入不为空有数据的那个,这样我们才能就一个在出的时候将前面数据移过去,出队列
要知道哪个空队列,写个函数就好了
还有就是移数据也可以单独写个函数,方便后面调用,并最好都设为私有,外面看不到,这样只能看到那些栈有的接口,更好一些
private:
void PutEmpty()
{
QEmpty();
while (nonemptyq->size() > 1)
{
emptyq->push(nonemptyq->front());
nonemptyq->pop();
}
}
void QEmpty()
{
if (_q2.empty())
{
swap(emptyq, nonemptyq);
}
}
其它的也就没什么了,不说了,上全部代码
class TwoQueueOneStack
{
public:
void Push(const int&x)
{
//入时入非空的队列
QEmpty();
nonemptyq->push(x);
}
void Pop()
{
PutEmpty();
nonemptyq->pop();
}
int& Top()
{
QEmpty();
return nonemptyq->back();
}
bool Empty()
{
return _q1.empty() && _q2.empty();
}
size_t Size()
{
return _q1.size() + _q2.size();
}
private:
void PutEmpty()//移数据
{
QEmpty();
while (nonemptyq->size() > 1)
{
emptyq->push(nonemptyq->front());
nonemptyq->pop();
}
}
void QEmpty()
{
if (_q2.empty())
{
swap(emptyq, nonemptyq);
}
}
private:
queue<int> _q1;
queue<int> _q2;
queue<int>* emptyq = &_q1;
queue<int>* nonemptyq = &_q2;
};
void test3()
{
TwoQueueOneStack s;
s.Push(1);
s.Push(2);
s.Push(3);
s.Push(4);
s.Pop();
cout << s.Top()<<endl;//3
s.Push(5);
cout << s.Top() << endl;//5
}
以上,今天总结完毕,剩下的以后再写吧!
———-【菜鸟日记】by 小宣子