题目:
正如本文题目所示,要求实现一个除了push,pop之外,还提供一个在O(1)时间内给出堆栈内最小的数值的操作。
解析1:
对于这个问题,我们可以从堆栈节点保存的信息入手。通常堆栈的节点只保存一个数据对象,为了能够在O(1)的时间内找到堆栈内最小的值,我们可以在每个堆栈节点内保存一个min值,用于指示堆栈在该节点及其以下的所有节点中,最小的值。这样,当需要获取堆栈中目前的最小值的时候,我们只需要获取栈顶节点的min数据即可。
根据这种思想,我们不难写出代码:
#include <iostream>
#include <string>
using namespace std;
class OutofDataException
{
public:
OutofDataException(const string& msg);
string message() const;
private:
string _msg;
};//class OutofDataException
OutofDataException::OutofDataException(const string& msg)
:_msg(msg) {}
string OutofDataException::message() const
{
return _msg;
}//
class StackWithMin
{
public:
StackWithMin();
StackWithMin(const StackWithMin& rhs);
~StackWithMin();
StackWithMin& operator=(const StackWithMin& rhs);
void push(int data);
int pop();
int min() const;
int size() const;
bool isEmpty() const;
private:
void destroy(); //用于销毁栈,回收内存空间
struct Node //堆栈节点类型
{
int data;
int min;
Node* next;
Node* clone() const;
};//Node
Node* _top;
int _size;
};//class StackWithMin
typedef StackWithMin STW;
STW::Node* STW::Node::clone() const
{
Node* p = new Node;
if(p == NULL) throw "Memory allocation failure!\n";
p->data = data;
p->min = min;
p->next = NULL;
const Node* q = this;
while(q->next != NULL)
{
p->next = new Node;
p = p->next;
q = q->next;
p->data = q->data;
p->min = q->min;
p->next = NULL;
}
return p;
}//STW::Node::copy
STW::StackWithMin():_top(NULL), _size(0) {}
STW::StackWithMin(const StackWithMin& rhs)
:_top(NULL), _size(rhs._size)
{
if(rhs._size == 0) return;
_top = rhs._top->clone();
}//STW::StackWithMin
STW::~StackWithMin()
{
destroy();
}//STW::~StackWithMin
StackWithMin& STW::operator=(const StackWithMin& rhs)
{
if(this == &rhs) return *this;
Node* p = NULL;
if(rhs._top != NULL) p = rhs._top->clone();
destroy();
_size = rhs._size;
_top = p;
return *this;
}//STW::operator=
void STW::push(int data)
{
Node* p = new Node;
if(p == NULL) throw "Memory allocation failure!\n";
p->data = data;
if(_top == NULL)
{
p->min = data;
p->next = NULL;
}
else
{
p->next = _top;
p->min = (data<_top->min)?data:_top->min;
}
_top = p;
_size++;
}//STW::push
int STW::pop()
{
if(_size == 0) throw OutofDataException("堆栈为空\n");
Node* p = _top;
_top = _top->next;
_size--;
int t = p->data;
delete p;
return t;
}//STW::pop
int STW::min() const
{
if(_size == 0) throw OutofDataException("堆栈为空\n");
return _top->min;
}//STW::min
void STW::destroy()
{
if(_size == 0) return;
_size = 0;
while(_top!= NULL)
{
Node* p = _top;
_top = _top->next;
delete p;
}
}//STW::destroy
bool STW::isEmpty() const
{
return (_size == 0);
}//STW::isEmpty
int main()
{
StackWithMin s;
int x = 0;
while(cin >> x && x >= 0)
{
s.push(x);
}
while(!s.isEmpty())
{
cout << s.min() << " " << endl;
s.pop();
}
getchar();
}
解析2:
用上面的方法能够正确的提供题目所要求的方法,但是这种方法所需的空间复杂度为O(n),n为堆栈元素个数。我们其实可以做到更好,使空间复杂度在最好的情况下降为O(1),最坏的情况下为O(n).这种方法中,我们并不直接修改堆栈节点类型,而是用另外一个堆栈来保存最小值的信息。其中,保存最小值的辅助栈的节点信息中保存当前栈的最小值,以及栈中包含最小值的节点的个数。
每次入栈时,有三种情况:
1.当入栈元素值小于当前堆栈的最小元素时,才将该值以及计数值(为1)同时放入辅助栈;
2.当入栈值大于栈的最小值时,存放最小值的栈不需要做任何改变;
3.当入栈值等于当前栈的最小值时,将最小值栈栈顶节点的最小值计数加一。
每次出栈时同样包含两种情况:
1.当出栈元素值大于当前栈的最小值,只需将其从栈中弹出即可,无需对辅助栈进行任何改变;
2.当出栈元素值等于当前栈的最小值,则将辅助栈栈顶节点中的计数信息减一,当计数为零时,弹出栈顶元素;
每次要获取栈中最小元素值,只需要获取辅助栈栈顶元素的值即可。
根据这种思路,则不难给出代码:
#include <stack>
#include <iostream>
using namespace std;
class StackWithMin
{
public:
StackWithMin();
~StackWithMin();
void push();
int pop();
int min();
bool isEmpty() const;
int size() cosnt;
private:
stack<int> mainStack;
stack<pair<int, int> > minStack;
};//class StackWithMin
typedef StackWithMin STW;
STW::StackWithMin():_size(0) {}
STW::~StackWithMin() {}
void STW::push(int data)
{
mainStack.push(data);
if(minStack.empty())
{
minStack.push(make_pair(data, 1));
}
else if(data == minStack.top().first)
{
minStack.top().second++;
}
}//STW::push
int STW::pop()
{
if(mainStack.empty()) throw "Stack is empty\n";
int top = mainStack.top();
mainStack.pop();
if(top == minStack.top().first)
{
minStack.top().second--;
if(minStack.top().second == 0) minStack.pop();
}
return top;
}//STW::pop
int STW::size() const
{
return mainStack.size();
}//STW::size
int STW::isEmpty() const
{
return mainStack.empty();
}//STW::isEmpty