实现一个在O(1)内提供min操作的栈

来源:互联网 发布:精修图片软件 编辑:程序博客网 时间:2024/05/19 15:21

题目:

正如本文题目所示,要求实现一个除了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 OutofDataExceptionOutofDataException::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;};//NodeNode* _top;int _size;};//class StackWithMintypedef 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::copySTW::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::StackWithMinSTW::~StackWithMin(){destroy();}//STW::~StackWithMinStackWithMin& 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::pushint STW::pop(){if(_size == 0) throw OutofDataException("堆栈为空\n");Node* p = _top;_top = _top->next;_size--;int t = p->data;delete p;return t;}//STW::popint STW::min() const{if(_size == 0) throw OutofDataException("堆栈为空\n");return _top->min;}//STW::minvoid STW::destroy(){if(_size == 0) return;_size = 0;while(_top!= NULL){Node* p = _top;_top = _top->next;delete p;}}//STW::destroybool STW::isEmpty() const{return (_size == 0);}//STW::isEmptyint 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 StackWithMintypedef 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::pushint 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::popint STW::size() const{return mainStack.size();}//STW::sizeint STW::isEmpty() const{return mainStack.empty();}//STW::isEmpty


原创粉丝点击