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

题目:

正如本文题目所示,要求实现一个除了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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值