1、设计一个包含min函数的栈,要求min,pop,push的时间复杂度都是o(1),两种解法。
思路:设计两个栈主栈和min栈,主栈就是正常栈,负责pop()和push(),min栈,专门用来存储当前最小的元素,负责min函数。min栈的设计思路有两种,
(1)min栈的大小和主栈的一样大,当有元素入栈时就和当前栈顶元素比较,如果当前入栈元素小于min栈的元素,直接入栈,否则,将min栈种的top元素入栈。出栈时直接出。
(2)min栈比主栈小,当有元素入栈时就和当前栈顶元素比较,如果当前入栈元素小于等于min栈的元素,直接入栈,否则,跳过。出栈时,如果当前主栈top和min栈的top一样大,min栈就弹栈,否则,跳过。((1)(2)中所提到的栈都是min栈,主栈就是正常进出栈)。
typedef int ElemType;
class Stack
{
public:
ElemType getMinElemType();
void push(ElemType value);
void pop();
void Push(ElemType value);
void Pop();
protected:
stack<ElemType> mainStack;
stack<ElemType> minStack;
};
ElemType Stack::getMinElemType()
{
ElemType value=INT_MAX;
if (!minStack.empty())
{
value = minStack.top();
}
return value;
}
void Stack::push(ElemType value)
{
mainStack.push(value);
if (minStack.empty())
{
minStack.push(value);
}
else
{
if (value < minStack.top())
{
minStack.push(value);
}
else
{
minStack.push(minStack.top());
}
}
}
void Stack::pop()
{
if (!mainStack.empty())
{
mainStack.pop();
minStack.pop();
}
}
void Stack::Push(ElemType value)
{
mainStack.push(value);
if (minStack.empty())
{
minStack.push(value);
}
else
{
if (value <= minStack.top())
{
minStack.push(value);
}
}
}
void Stack::Pop()
{
if (!mainStack.empty())
{
if (mainStack.top() == minStack.top())
{
minStack.pop();
}
mainStack.pop();
}
}
2、用两个栈实现一个队
思路:设计两个栈,主栈和辅助栈,当有元素需要进时,将元素放入主栈。当有元素需要出栈时,判断辅助栈是否为空,如果不为空,将辅助栈的栈顶出栈,如果为空,将主栈中的元素全部放入辅助栈中,在将辅助栈栈顶出栈。
栈空:主栈和辅助栈同时为空。
栈满:主栈满且辅助栈中有元素。
class Queue
{
protected:
stack<ElemType> mainStack;
stack<ElemType> auxiliaryStack;
public:
void pushQueue(ElemType value);
void popQueue();
bool queueEmpty();
bool queueFill();
};
void Queue::pushQueue(ElemType value)
{
//将数据放在主栈中
mainStack.push(value);
}
void Queue::popQueue()
{
if (!queueEmpty())
{
//辅助栈为空。将主栈中的元素全部放入辅助栈中。
if (auxiliaryStack.empty())
{
while (!mainStack.empty())
{
auxiliaryStack.push(mainStack.top());
mainStack.pop();
}
}
//测试
//cout << auxiliaryStack.top() << endl;
auxiliaryStack.pop();
}
}
bool Queue::queueEmpty()
{
bool bRef = false;
if (mainStack.empty() && auxiliaryStack.empty())
{
bRef = true;
}
return bRef;
}
bool Queue::queueFill()
{
//如果主栈满了,且辅助栈中有元素,就说明队满,但STL中栈不会满,这里就不实现了.
return false;
}
3、用两个队实现一个栈
思路:设计主队和辅助队,当有元素入栈时,判断如果两队都为空,则元素进入主队,如果存在不为空的队,将元素进入此队。出队,将不为空的队中的除队尾元素之外的其他所有元素全部移入空队中,将原队中的队尾元素出队。
队满:任意一个队满,就是栈满。
队空:两队同时为空。
class userStack
{
protected:
queue<ElemType> mainQueue;
queue<ElemType> auxiliaryQueue;
public:
void pushStack(ElemType value);
void popStack();
bool stackEmpty();
bool stackFill();
};
void userStack::pushStack(ElemType value)
{
//辅助栈空或如果两个队都空,将元素进入主栈。
if (auxiliaryQueue.empty()||(mainQueue.empty() && auxiliaryQueue.empty()))
{
mainQueue.push(value);
}
else
{
auxiliaryQueue.push(value);
}
}
void userStack::popStack()
{
if (!stackEmpty())
{
if (!mainQueue.empty())
{
while (mainQueue.size() > 1)
{
auxiliaryQueue.push(mainQueue.front());
mainQueue.pop();
}
cout << mainQueue.front() << endl;
mainQueue.pop();
}
else
{
while (auxiliaryQueue.size() > 1)
{
mainQueue.push(auxiliaryQueue.front());
auxiliaryQueue.pop();
}
cout << auxiliaryQueue.front() << endl;
auxiliaryQueue.pop();
}
}
}
bool userStack::stackEmpty()
{
bool bRef = false;
if (mainQueue.empty() && auxiliaryQueue.empty())
{
bRef = true;
}
return bRef;
}
bool userStack::stackFill()
{
//当任意一个队满,就说明栈满。
return false;
}
4、给定序列和一个出栈顺序,计算出栈顺序是否正确
思路:先让给定的入栈和出栈的序列相比较,如果两个序列中第一个元素相同,则和第二个比较……直到序列中元素不相同,或者序列全部比较完毕。
(1)如果序列比较完毕,直接返回“真”。
(2)如果序列没有比完,申请一个栈,则将入栈序列依此进栈,每进一个元素就用当前栈顶元素和出栈序列中的元素相同就将该元素出栈,继续判断栈顶元素和出栈序列中的下一个是否相同。循环结束后判断栈是否为空。为空则说明出栈序列正确,不为空出栈序列不正确。
bool judgePushOrder(int* pushOrder, int* popOrder, int orderLen)
{
int i = 0;
bool bRet = false;
//如果匹配成功说明当前元素是先进栈,然后直接出栈
while (i<orderLen&&pushOrder[i] == popOrder[i])
{
++i;
}
if (i == orderLen)
{
bRet = true;
}
else
{
//将剩余的元素比较
stack<ElemType> Stack;
int j = i;
while (i<orderLen)
{
Stack.push(pushOrder[i]);
//总体入栈的顺序是一定的
while (Stack.size() > 0 && Stack.top() == popOrder[j])
{
Stack.pop();
++j;
}
++i;
}
if (Stack.size() == 0)
{
bRet = true;
}
}
return bRet;
}
5、递归逆序栈。不能申请新的数据结构
思路:在递归的每一次拿到当前栈低的元素,并将其出栈,在递归结束后,将该元素重新入栈。
/*
假设入栈顺序为1,2,3,4,5
递归过程:
5,4,3,2,1 1
5,4,3,2 2
5,4,3 3
5,4 4
5 5
*/
ElemType getStackLastValue(stack<ElemType>& Stack)
{
//保存每次Pop的数据
ElemType r = Stack.top();
Stack.pop();
if (Stack.empty())
{
//栈底元素
return r;
}
ElemType lastValue = getStackLastValue(Stack);
Stack.push(r);
return lastValue;
}
void reverseStack(stack<ElemType>& Stack)
{
if (Stack.empty())
{
return;
}
//要使的r为栈底元素
//依此返回了1,2,3,4,5
ElemType lastValue = getStackLastValue(Stack);
reverseStack(Stack);
//入栈顺序为5,4,3,2,1
Stack.push(lastValue);
}
6、栈排序(升序)。
思路:申请一个辅助栈,将主栈中的栈顶元素存起来,然后出栈,让它和当前栈顶元素相比较,如果取出的元素大于,当前栈顶元素,将栈顶元素放入辅助栈中,并重原栈中弹出。取出元素小于等于当前栈顶元素,将取出元素放入辅助栈中。这样比完之后主栈中剩余的元素就是当前最大的元素。将此元素取出并保存,将辅助中第i个之前的元素全部放入主栈中,(i为主循环次数)。知道主栈为空,那辅助栈中就是排序好的元素。
//升序
void sortStack(stack<ElemType>& Stack)
{
stack<ElemType> pStack;
ElemType value;
int i = 0;//记录主循环次数
while (!Stack.empty())
{
while (Stack.size() > 1)
{
value = Stack.top();
Stack.pop();
if (value > Stack.top())
{
//如果取出的元素大于,当前栈顶元素,将栈顶元素放入辅助栈中,并重原栈中弹出。
pStack.push(Stack.top());
Stack.pop();
//将取出元素入栈
Stack.push(value);
}
else
{
//取出元素小于等于当前栈顶元素,将取出元素放入辅助栈中。
pStack.push(value);
}
}
//当前栈中最大元素
ElemType t = Stack.top();
Stack.pop();
//第i的下面都是排好序的
while (int (pStack.size()) > i)
{
Stack.push(pStack.top());
pStack.pop();
}
//将最大元素放入辅助栈中
pStack.push(t);
++i;
}
Stack = pStack;
}
n个结点的的二叉树有多少种形式?
卡特兰数,还用在n个元素出栈的可能性次数,以及二叉树的中序序列已知,求二叉树的种类的个数。