看本文之前,推荐本博客的http://blog.csdn.net/lsjseu/article/details/9351141,熟悉一下STL中序列容器的接口以及内部实现结构。
我先谈一谈栈和队列的基本情况:栈是一种后进先出的结构,STL里面为我们编好了栈,但是我们也可以自己实现。通常有两种实现方式,一种是静态数组或者动态数组的实现方式(在这里,实现的时候,注意如果栈空间满了以后,我们提供扩从容量的策略会比较好),第二种是同过链表的实现方式。运用到栈的算法有哪些呢:括号匹配问题,中缀表达式转后缀表达式问题,迷宫路径搜索问题,非递归遍历问题,回溯搜索问题,递归转非递归。
再谈谈队列:队列是一种先进先出的结构,队列有双端队列,优先级队列,循环队列。队列也有两种简单的实现方式,一种是通过静态数组或者动态数组,一种是通过链表实现。那么队列被哪些算法用到了:杨式三角,迷宫最短路径搜索(注意这里是最短路径,而用栈的话只能搜索路径,不一定是最短),广度优先遍历问题,层次遍历问题(其实这是广度优先的一个特例),进程调度(优先级队列,堆),
本文搜集了一下关于栈和队列的一些算法。
(1)用两个栈构成一个队列。
算法很简单,一个栈负责“插入”,一个栈负责“弹出”。当弹出的栈没有元素的时候,要从插入的栈把元素全部搬过来。
class MyQueue{
private:
stack<int> insertStack;
stack<int> popStack;
public:
int Dequeue(){
if(popStack.empty()){
if(insertStack.empty())
throw new runtime_error("Null Queue");
while(!insertStack.empty()){//把元素挪过来
popStack.push(insertStack.top());
insertStack.pop();
}
}
int result = popStack.top();
popStack.pop();
return result;
}
void Enqueue(int elem){
insertStack.push(elem);
}
};
我这里只是简单的实现了pop和push两种操作,没有去实现STL里面关于队列的其他接口。详细参见本博客:
http://blog.csdn.net/lsjseu/article/details/9108711
记得在“July微软面试百题系列”里面有个在多线程下实现队列的pop和push操作。我的理解是在pop和push操作的时候需要“加锁”。
(2)两个队列实现一个栈
这个算法需要用两个队列来回倒腾。下面简单的实现以下。看不懂的话同样可以参考:http://blog.csdn.net/lsjseu/article/details/9108711
class MyStack{
private:
queue<int> q1;
queue<int> q2;
public:
int Pop(){
if(q1.empty() && q2.empty())
throw new runtime_error("Null Stack");
int result;
if(q1.empty()){
while(q2.size() != 1){
q1.push(q2.front());
q2.pop();
}
result = q2.front();
q2.pop();
return result;
}
if(q2.empty()){
while(q1.size() != 1){
q2.push(q1.front());
q1.pop();
}
result = q1.front();
q1.pop();
return result;
}
}
void Push(int elem){
if(q1.empty() && q2.empty()){//两者都为空,随便插进那个都无所谓
q1.push(elem);
}
else if(q1.empty())
q2.push(elem);
else
q1.push(elem);
}
};
剑指offer上给出的解答是构造一个辅助的栈去存储最小值,同样,在编程之美上也给出了同样的答案,只不过编程之美上给出的答案是保持最小值的索引。下面简单的实现了下:
template<class T>
class MinStack{
private:
stack<T> st;
stack<T> minst;
public:
void Push(T t){
st.push(t);
if(minst.empty() || (t<minst.top()))//要求T重载了"<"
minst.push(t);
else
minst.push(minst.top());
}
T Pop(){
int popNum;
if(!st.empty()){
popNum = st.top();
st.pop();
minst.pop();
}
else
throw new runtime_error("Empty Stack");
return popNum;
}
T GetMin(void)const{
return minst.top();
}
T IsEmpty()const{
return st.empty();
}
};
(4)包含min函数的队列(编程之美)
其实队列和栈和上面是一样的,我们不能简单的用上面的这种方案来解答。想想就知道了。对此编程之美给出了两种答案:
第一种方案:构造一个特殊的最大堆,但是这个堆包含有队列的指针,能够以o(lgn)去插入和删除,得到最小值时间复杂度为o(1);
第二种方案:利用上面的构造含有min函数的栈来构造这个特殊的队列。
template<class T>
class MinStack{
private:
stack<T> st;
stack<T> minst;
public:
void Push(T t){
st.push(t);
if(minst.empty() || (t<minst.top()))//要求T重载了"<"
minst.push(t);
else
minst.push(minst.top());
}
T Pop(){
int popNum;
if(!st.empty()){
popNum = st.top();
st.pop();
minst.pop();
}
else
/*throw std::runtime_error("Empty Stack");*/
cout<<"Null Stack"<<endl;
return popNum;
}
T GetMin(void)const{
return minst.top();
}
T IsEmpty()const{
return st.empty();
}
};
template<class T>
class MinQueue{
private:
MinStack<T> sta;
MinStack<T> stb;
public:
T GetMin()const{
if(sta.IsEmpty() && stb.IsEmpty())
throw new runtime_error("Null Stack");
else if(!sta.IsEmpty() && stb.IsEmpty())
return sta.GetMin();
else if(sta.IsEmpty() && !stb.IsEmpty())
return stb.GetMin();
else return min(sta.GetMin(),stb.GetMin());
}
void Enqueue(T t){
sta.Push(t);
}
T Dequeue(){
if(stb.IsEmpty()){
while(!sta.IsEmpty()){
stb.Push(sta.Pop());
}
}
return stb.Pop();
}
};
(4)打印堆栈
#include <iostream>
#include <stack>
using namespace std;
void PrintStack(stack<int>& st)
{
if(st.empty())
return;
int top = st.top();
cout<<top<<" ";
st.pop();
PrintStack(st);
st.push(top);
}
int main()
{
stack<int> st;
st.push(1);
st.push(2);
st.push(3);
PrintStack(st);
cout<<endl;
PrintStack(st);//打印两遍,验证堆栈有没有被改变
system("pause");
return 0;
}
(5)给堆栈中的元素排序
啥也不说了,直接看程序。当然这里可以转化为非递归的方法去实现。
#include <iostream>
#include <stack>
using namespace std;
void PrintStack(stack<int>& st)
{
if(st.empty())
return;
int top = st.top();
cout<<top<<" ";
st.pop();
PrintStack(st);
st.push(top);
}
void SortStack(stack<int>& st)
{
if(st.empty())return;
int topNum = st.top();
st.pop();
SortStack(st);//顶元素弹出,将下面的排好
stack<int> tempSt;
while(!st.empty() && st.top()>topNum){
tempSt.push(st.top());
st.pop();
}
st.push(topNum);
while(!tempSt.empty()){
st.push(tempSt.top());
tempSt.pop();
}
}
int main()
{
stack<int> st;
st.push(1);
st.push(4);
st.push(3);
PrintStack(st);
SortStack(st);
cout<<endl;
PrintStack(st);//打印两遍,验证堆栈有没有被改变
system("pause");
return 0;
}
#include <iostream>
#include <stack>
#include <cassert>
using namespace std;
void PrintArr(int arr[],int len){
assert(arr && len>=0);
for(int i=0; i<len; ++i){
cout<<arr[i]<<" ";
}
cout<<endl;
}
void InsertSortRecursively(int arr[],int index){
assert(arr && index>=0);
if(index == 0) return;
int base = arr[index];
InsertSortRecursively(arr,index-1);//我们假设前面排好序了
int i = index-1;
while(i>=0 && arr[i]>base){
arr[i+1] = arr[i];
i--;
}
arr[i+1] = base;
}
int main()
{
const int LEN = 4;
int arr[LEN] = {3,2,4,5};
PrintArr(arr,LEN);
InsertSortRecursively(arr,LEN-1);
PrintArr(arr,LEN);
system("pause");
return 0;
}
(6)栈的逆序问题(准确的说是不能用额外的栈作为辅助空间)
#include <iostream>
#include <stack>
using namespace std;
void PrintStack(stack<int>& st)
{
if(st.empty())
return;
int top = st.top();
cout<<top<<" ";
st.pop();
PrintStack(st);
st.push(top);
}
void MoveButtomToTop(stack<int>& st)//将栈底部元素挪到顶部
{
if(st.empty())return;
int top1 = st.top();//接下来把栈顶元素弹出
st.pop();
if(!st.empty()){
MoveButtomToTop(st);//这里我们假设将栈底部元素挪上来了
int top2 = st.top();
st.pop();
st.push(top1);
st.push(top2);//此时将top1和top2交换就完成了我们的操作
return;
}
st.push(top1);
}
void ReverseStack(stack<int>& st)
{
if(st.empty())return;
MoveButtomToTop(st);
int topNum = st.top();
st.pop();
ReverseStack(st);
st.push(topNum);
}
int main()
{
stack<int> st;
st.push(1);
st.push(4);
st.push(3);
PrintStack(st);
ReverseStack(st);
cout<<endl;
PrintStack(st);
system("pause");
return 0;
}
(7)将栈顶元素移到栈底部(借鉴上面的算法)
#include <iostream>
#include <stack>
using namespace std;
void PrintStack(stack<int>& st)
{
if(st.empty())
return;
int top = st.top();
cout<<top<<" ";
st.pop();
PrintStack(st);
st.push(top);
}
void MoveTopToButtom(stack<int>& st){
if(st.empty())return;
int firstTop = st.top();
st.pop();
if(!st.empty()){
int secondTop = st.top();
st.pop();
st.push(firstTop);
MoveTopToButtom(st);
st.push(secondTop);
return;
}
st.push(firstTop);
}
int main()
{
stack<int> st;
st.push(1);
st.push(4);
st.push(3);
PrintStack(st);
MoveTopToButtom(st);
cout<<endl;
PrintStack(st);
system("pause");
return 0;
}
(8)栈的逆序问题(准确的说是不能用额外的栈作为辅助空间)
上面第(6)题其实已经实现了一个栈的翻转,但是本题想借鉴(7)来实现栈的翻转。
#include <iostream>
#include <stack>
using namespace std;
void PrintStack(stack<int>& st)
{
if(st.empty())
return;
int top = st.top();
cout<<top<<" ";
st.pop();
PrintStack(st);
st.push(top);
}
void MoveTopToButtom(stack<int>& st){ //把栈顶元素挪到栈底部
if(st.empty())return;
int firstTop = st.top();
st.pop();
if(!st.empty()){
int secondTop = st.top();
st.pop();
st.push(firstTop);
MoveTopToButtom(st);
st.push(secondTop);
return;
}
st.push(firstTop);
}
void ReverseStack(stack<int>& st){
if(st.empty())return;
int topNum = st.top(); //先将顶部元素弹出
st.pop();
ReverseStack(st);//假设除了顶部元素外,其他都被翻转了
st.push(topNum);//把栈顶元素压进去
MoveTopToButtom(st);//接下来的工作就是把栈顶元素挪到栈的底部
}
int main()
{
stack<int> st;
st.push(1);
st.push(2);
st.push(3);
PrintStack(st);
ReverseStack(st);
cout<<endl;
PrintStack(st);
system("pause");
return 0;
}
(9)给定栈的入栈序列,判断给定的序列是否可能是该序列的出栈序列。(剑指offer134页)
这个题用辅助栈来解答。
#include <iostream>
#include <stack>
#include <cassert>
#include <string>
using namespace std;
bool IsPopOrder(int pushSeq[],int popSeq[],int len)
{
assert(pushSeq && popSeq && len>0);
stack<int> st;
int i,j = 0;
for(i=0; i<len; ++i){
int popNum = popSeq[i];
while(st.empty() || st.top()!=popNum){
st.push(pushSeq[j++]);
if(j == len)break;
}
if(st.top() != popNum)
break;
st.pop();
}
if(st.empty() && i==len)
return true;
else return false;
}
int main()
{
const int SIZE = 5;
int pushSeq[SIZE] = {1,2,3,4,5};
int popSeq[SIZE] = {4,5,3,2,1};
string result = IsPopOrder(pushSeq,popSeq,SIZE)?"True":"False";
cout<<result<<endl;
system("pause");
return 0;
}
这里说明一下:给定栈的入栈序列,出栈的序列可能有多少种。(这是一个卡特兰数)类似的问题,包括给定前序遍历,中序遍历的有多少种?括号匹配问题。1,2,5......详细参考:http://blog.csdn.net/lsjseu/article/details/11827109