一 问题描述:
两个数组pPush和pPop分别存储了压栈序列和出栈序列,如何判断出栈序列是否正确,假设元素不重复。
需要实现的函数:
bool isStackOutRight(int *stackIn,int *stackOut,int length)
二 举例:
pPush中序列为:[5 9 1 8 13 4 2 7]
给出一个出栈序列pPop:[8 4 13 1 7 2 9 5],这个出栈序列是正确的。
给出另一个出栈序列pPop:[8 4 13 1 5 4 2 7 9],这个出栈序列就是错误的,因为8第一个出栈,说明栈中已经压入过5 9 1三个元素,它们还存在栈中
它们的出栈顺序必须满足 1 9 5 这个顺序(可以不连续,但是1在9前,9在5前),但是出栈队列中给出的顺序是1 5 9,所以是错误的。
三 算法思路:
需要用到一个辅助栈stackData来存储压入栈而尚未出栈的元素
现在举错误的出栈顺序为例:pPop:[8 4 13 1 5 4 2 7 9]
1 对出栈序列进行遍历,第1个元素是8,说明前面已经存过5 9 1,将它存入辅助栈中
在压入辅助栈的操作中,我们需要遍历压栈序列pPush:[5 9 1 8 13 4 2 7]
(1) [5 9 1 8 13 4 2 7] index指向首元素5,不等于元素8 ,将5压入辅助栈
(2) [5 9 1 8 13 4 2 7] index指向元素9不等于元素8 ,将9压入辅助栈
(3) [5 9 1 8 13 4 2 7] index指向元素1不等于元素8 ,将1压入辅助栈
(4) [5 9 1 8 13 4 2 7] index指向元素8等于元素8 ,相等时不压入,因为还要弹出
(5) [5 9 1 8 13 4 2 7] index指向下一个元素,以便下次压入操作
压栈结束后
stackData: 1 9 5】 (“】”形象的表示栈开口方向向左,1是栈顶元素)
可以看出,压入辅助栈的关键是压栈序列中的元素是否等于目前的遍历元素(8),不等于压入,等于就不再压入
2 遍历第2个元素是4,它不等于stackData中的top元素1,说明它可能(也可能存在于辅助栈)是新压入的元素,那么容易知道4之前的元素13已经被压入栈中,所以将13压入辅助栈
stackData: 13 1 9 5】
index指向下一个元素2
[5 9 1 8 13 4 2 7]
3 遍历第3个元素是13,它等于是stackData中的top元素13,说明没有新压入元素,只是弹出元素,所以辅助栈需要弹出top元素13
stackData: 1 9 5】
4 遍历第4个元素是1,它等于现在stackData中的top元素1,说明没有新压入元素,只是弹出元素,所以辅助栈需要弹出top元素1
stackData: 9 5】
5 遍历第5个元素是5,它不等于现在stackData中的top元素9,说明它可能是新压入的元素,也可能是辅助栈中的元素
情况1:如果是新压入的元素,那么出栈顺序到现在为止还是正确的
情况2:如果是辅助栈中的元素(已经知道不是首元素),就可以知道出栈序列是错误的,因为如果是辅助栈中的元素,出栈顺序必须和辅助栈一致,也就是必须是先9后5
问题的关键是怎么判断这种情况是情况1还是情况2
可以这样做,将这种情况看做是情况1,那么需要继续向辅助栈中压入元素,但是会发现将压栈序列中全部元素都压入辅助栈后依然找不到一个元素等于当前遍历元素5
在第2步后,index已经指向了2
(1) [5 9 1 8 13 4 2 7] index指向元素2不等于元素5 ,将2压入辅助栈
(2) [5 9 1 8 13 4 2 7] index指向元素7不等于元素5 ,将7压入辅助栈
现在index已经指向了最后一个元素,但是没有找到等于5的元素,那么可以断言,5其实是在辅助栈中的,这种情况属于情况2,因此出栈序列是不正确的
四 伪代码
int index = 0
for 遍历出栈序列
if (辅助栈不空 && 辅助栈top元素等于pPop[i])
辅助栈弹出top元素
else //辅助栈为空 或者 top元素不等于pPop[i],要压入元素了
while(pPush[index] 不等于 pPop[i]) //只压入pPop[i]之前的元素,本身不压入
辅助栈压入pPush[index] 元素
index++
if (index 等于 length)//说明没有找到这个元素标记,pPop[i]一定在辅助栈中,出栈序列错误
return false
else
index++ //要指向下一个元素
return true //for 循环能正常结束,出栈序列就一定是正确的
五 代码
1 C++版本
1 bool isStackOutRight(int *stackIn,int *stackOut,int length){ 2 stack<int> stackData;//辅助栈 3 int index(0); 4 for (int i = 0;i<length;i++){//遍历整个出栈序列 5 6 if (!stackData.empty() && stackData.top() == stackOut[i]) //辅助栈不空,而且遍历的元素是辅助栈的top元素,需要弹出操作 7 stackData.pop(); 8 else { //辅助栈为空,或者不等于首元素,指向压栈操作 9 while(index<length && stackIn[index] != stackOut[i]) 10 stackData.push(stackIn[index++]); 11 if (index == length)//这里是关键,说明在压栈序列中从index开始往后遍历,没有找到该元素,该出栈序列不正确 12 return false; 13 else 14 index++; 15 } 16 } 17 return true;//整个for循环能正常结束(没有遇到return false),说明出栈序列正确 18 }