队列和栈相关面试题总结

1、实现一个栈,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值的操作)的时间复杂度为O(1)??
分析:
     出栈和入栈根据栈自身提供的接口不难实现,而返回最小值,我们知道遍历一次栈即可找到最小值,但是对栈的操作只能在栈顶,因此,要遍历势必要改变栈的状态,而且还要求时间复杂度为O(1),即更不能遍历栈。我们可以利用两个栈同时进行操作,一个是我们放数据的栈,而另一个栈顶专门放数据中的最小值,最后需要当前最小值,直接取第二个栈顶元素即可。

2、源代码如下:
//push出栈   ------     pop入栈           min返回最小值 ------   时间复杂度为O(1)

//不能遍历

#include <iostream>
using namespace std;
#include <stack>

template <class T>
class StackMinValue
{
public:
	StackMinValue()
	{}
	void Pop(const T& x)
	{
		s.push(x);
		if(min.empty())
		{
			min.push(x);
		}
		else if(min.top()>=x)
		{
			min.push(x);
		}
	}
	void Push()   //出栈
	{
		if(min.top() == s.top() && s.size() != 1) 
		{
			min.pop();
		}
		s.pop();
	}
	T& Min()
	{
		return min.top();
	}
	~StackMinValue()
	{}
private:
	stack<T> s,min;
};



int main()
{
	StackMinValue<int> a;
	a.Pop(3);
	a.Pop(2);
	cout<<a.Min();
	a.Pop(5);
	a.Pop(8);
	a.Pop(1);
	cout<<a.Min();
	a.Push();
	a.Push();
	cout<<a.Min();
	a.Push();
	a.Push();
	cout<<a.Min();

	return 0;
}
2、使用两个栈实现一个队列
分析:栈--->先进后出                        队列--->先进先出
在进行操作时,我们可利用栈的特性,在进行push操作时,使用栈操作,而进行pop操作时将栈中元素逐一放入另一栈
源代码:
#include <iostream>
using namespace std;
#include <stack>
#include <assert.h>
template<class T>
class Queue
{
public:
	Queue()
	{}
	void Push(const T& x)  //尾插
	{
		a.push(x);
	}
	void Pop()            //头删
	{
		assert(!a.empty());
		while(!a.empty())
		{
			b.push(a.top());
			a.pop();
		}
		b.pop();
		while(!b.empty())
		{
			a.push(b.top());
			b.pop();
		}
	}
	size_t Size()
	{
		return a.size();
	}
	bool Empty()
	{
		return a.empty();
	}
	T& front()     //返回队头元素 -------找到再恢复
	{
		assert(a.empty() != true);
		while (!a.empty())
		{
			b.push(a.top());
			a.pop();
		}
		T tmp = b.top();
		while (!b.empty())
		{
			a.push(b.top());
			b.pop();
		}
		return tmp;
	}
	T& back()     //返回队尾元素
	{
		return a.top();
	}
	~Queue()
	{}
private:
	stack<T> a,b;
};
int main()
{
	Queue<int> a;
	a.Push(1);
	a.Push(2);
	a.Push(3);
	cout<<a.front()<<endl;
	cout<<a.Size()<<endl;
	a.Push(4);
	a.Pop();
	cout<<a.front()<<endl;
	return 0;
}

3、两个队列实现栈
思路:栈---先进后出    队列---先进先出
创建两个队列,一个队列放数据,另一个当作辅助队列,当进行push(尾插)操作时直接用队列的push进行操作,而进行pop操作时,由于队列的pop是进行头删,不符合栈pop的条件,这时可将队列1中数据从第一个开始另一辅助队列2中,但是,第一个队列中最后一个元素不放入,然后,将第一个队列清空,再将辅助队列中元素按顺序放入第一个队列中即可。
源代码:
#include <iostream>
using namespace std;
#include <queue>
#include <assert.h>
// 两个队列实现一个栈
template <class T>
class TStack
{
public:
	TStack()
	{}
	void Push(const T& x) //进栈---尾插
	{
		s1.push(x);
	}
	void Pop()   //出栈---
	{
		assert(!s1.empty());
		while (!s1.empty() && (s1.size()!=1))    //最后一个元素不进队列
		{
			s2.push(s1.front());
			s1.pop();
		}
		s1.pop();
		while (!s2.empty())
		{
			s1.push(s2.front());
			s2.pop();
		}
	}
	bool Empty()
	{
		if (s1.empty())
		{
			return true;
		}
		return false;
	}
	T& Top()
	{
		return s1.back();
	}
	size_t Size()
	{
		return s1.size();
	}

private:
	queue<T> s1,s2;
};


int main()
{
	TStack<int> a;
	a.Push(1);
	a.Push(7);
	a.Push(5);
	a.Push(6);
	cout<<a.Top()<<endl;
	cout<<a.Size()<<endl;
	a.Pop();
	cout<<a.Size()<<endl;
	cout<<a.Top()<<endl;
	return 0;
}

4、一个数组实现两个栈
分析:

方案一:将数组的下标为0的位置当做第一个栈的栈底,下标为1的位置当做第二个栈的栈底,将数组的偶数位置看做第一个栈的存储空间,奇数位置看做第二个栈的存储空间。


方案二:从中间分别向两边压栈

将数组的中间位置看做两个栈的栈底,压栈时栈顶指针分别向两边移动,当任何一边到达数组的起始位置或是数组尾部,则开始扩容。


方案三:从两边向中间压栈

将数组的起始位置看作是第一个栈的栈底,将数组的尾部看作第二个栈的栈底,压栈时,栈顶指针分别向中间移动,直到两栈顶指针相遇,则扩容。


比较:方案二和方案一当两栈中元素不同时,比较浪费空间,方案三节省空间

方案3代码:

#include <iostream>
using namespace std;
#include <assert.h>
//一个数组实现两个栈 
//从两边开始存
template<class T>
class Stack
{
public:
	Stack()
		:_arr(NULL)    
		,_size1(0)
		,_size2(0)
		,_capacity(0)       //初始化容量为2
	{}
	void Push1(const T& x)
	{
		_checkcapacity();
		_arr[_size1] = x;
		_size1++;
	}
	void Pop1()
	{
		assert(Size1() != 0);
		_size1--;
	}
	size_t Size1()
	{
		return _size1;
	}
	T& Top1()
	{
		return _arr[_size1-1];
	}
	void Push2(const T& x)
	{	
		_checkcapacity();
		size_t botton = _capacity-_size2-1;
		_arr[botton] = x;
		botton--;
		_size2++;
	}

	void Pop2()
	{
		assert(Size2() != 0);
		_size2--;
	}
	size_t Size2()
	{
		return _size2;
	}
	T& Top2()
	{
		assert(_size2 != 0);
		return _arr[_capacity-1];
	}
private:
	void _checkcapacity()
	{
		if ((_size1+_size2)==_capacity || (_capacity==0))   //容量满 或 空
		{
			size_t _newcapacity = _capacity*2+2;
			T* tmp = new T[_newcapacity];
			for (size_t i=0; i<_size1; i++) //第一个栈放数组左边 
			{
				tmp[i] = _arr[i];
			}
			size_t t = _capacity-1;
			for(size_t j=_newcapacity-1; (j>(_newcapacity-_size1)) && (t>_size1-1); --t,j--)
			{
				tmp[j] = _arr[t];
			}
			_capacity = _newcapacity;
			swap(_arr,tmp);
		}
	}
private:
	T* _arr;
	size_t _size1;
	size_t _size2;
	size_t _capacity;
};

int main()
{
	Stack<int> a;
	a.Push1(1);
	cout<<a.Size1()<<endl;
	a.Push1(8);
	a.Pop1();
	a.Push1(5);
	a.Push1(3);
	cout<<a.Size1()<<endl;
	cout<<a.Top1()<<endl;
	a.Push1(2);
	a.Push2(1);
	a.Push2(0);
	a.Push2(4);
	cout<<a.Size2()<<endl;
	cout<<a.Top2()<<endl;
	a.Push2(1);
	a.Push2(1);
	a.Push2(4);
	a.Push2(10);
	a.Pop1();
	cout<<a.Size2()<<endl;
	a.Pop1();
	a.Pop2();
	a.Pop2();
	cout<<a.Size2()<<endl;
	cout<<a.Top2()<<endl;
	return 0;
}






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值