出栈序列的合法性

来源:互联网 发布:linux hello world 编辑:程序博客网 时间:2024/05/16 11:38

问题描述:对于一个进栈序列其出栈序列存在多种合法的可能情况。例如:入栈序列为1,2,3,4,5时,而对于出栈序列5,4,3,2,1、1,3,2,5,4、3,5,4,2,1等等这些都是一个合法的出栈序列,但是对于3,5,2,4,1、5,3,4,2,1等这种出栈序列则是非法的序列,因为其违背了栈的特性(先进后出或者后进先出)。



★对于1,2,3,4,5这样的进栈序列,我们最常想到的出栈序列为5,4,3,2,1。这是因为将其一次性逐个入栈,然后逐个弹出得到的出栈序列。然而在这里我们并未规定所有元素入栈后才相继弹出,所以这里的序列就很多很多了。

比如:以上述一个合法的出栈序列1,3,2,5,4为例:再比如:以上述一个非法的出栈序列3,5,2,4,1为例:

①栈为空,元素1入栈,然后弹出。①栈为空,元素1,2,3入栈,元素3弹出(此时栈内保留压入元素1,2)。

②元素2,3入栈,元素3,2分别弹出。 ②元素4,5入栈,此时栈内为1,2,4,5,然后元素5出栈(栈内剩余元素1,2,4)。

③元素4,5入栈,元素5,4分别弹出,得到该合法序列1,3,2,5,4。③此时要让元素2出栈,但是此时滞留在栈内的栈顶元素为4,所以该序列非法。


①在此我们先来看看数组的实现:

#include<iostream>using namespace std;int main(){int i, j, k;int temp;//存放第一个可能比s[i]小的数int num = 0;int flag1,flag2;//两个标志位,一个标记存在比s[i]小的数,另一个为标记序列的合法性cin >> num;int *s = new int[num]; //动态开辟数组,注意结束时的回收(delete[] s) for (i = 0; i < num; i++)cin >> s[i];for (i = 0; i < num; i++)//寻找是否存在比s[i]小的数{flag1 = 0;flag2 = 0;for (j = i + 1; j < num; j++)if (s[j]<s[i])//如果存在,则将其放入到temp变量中,并将flag1标志位置为1{temp = s[j];  flag1 = 1;break;}if (flag1 == 1)//在标志位为1的前提下,继续寻找是否仍存在比s[i]小的数,并且比temp小的数,存在则不断更新temp的值for (k = j + 1; k < num; k++)if (s[k]<s[i]) if (s[k]<temp) temp = s[k];else //否则将序列合法性的标志位置为1{flag2 = 1;break;}if (flag2 == 1)//非法的序列{cout << "illegal sequence!" << endl;exit(0); }}cout << "legal sequence!" << endl;//合法的序列        delete[] s;return 0;}

★注:分析上述的代码我们不难看出,对于入栈序列1,2,3,4,5来说,其判断一个出栈序列的合法性的标准为出栈序列中,元素i之后比其小的元素必须是降序排列的。



②数组有其局限性,比如整型数组存放整型值,字符数组存放字符串,所以我们可以利用指针来做,对于其类型的问题,我们可以借助模板来实现。

#include<iostream>    #include<stack>    #include<cstring>#include<cassert>  using namespace std;bool judge(const char *sour, const char *dest)//不比更改两个序列的内容,所以可加const修饰限定符{        assert(sour);<span style="white-space:pre"></span>//断言可防止NULL指针的传入(避免传入指针引起程序崩溃的问题)        assert(dest);stack<char> ss;<span style="white-space:pre"></span>//借助库函数创建一个栈if (strlen(sour) != strlen(dest))  <span style="white-space:pre"></span>//如果两个序列不一样长,自然是非法的序列return false;ss.push(*sour++); <span style="white-space:pre"></span>//将首元素压栈while (*dest != '\0')  {if (ss.empty() && *sour != '\0')  <span style="white-space:pre"></span>//如果栈为空且入栈序列未结束,则不断压入元素ss.push(*sour++);while (*dest != ss.top() && *sour != '\0') {ss.push(*sour++); <span style="white-space:pre"></span>//如果出栈元素和栈顶元素不匹配则继续压入元素}if (*dest == ss.top())  <span style="white-space:pre"></span>//如果两者相等,将该元素弹出,且指针指向出栈序列的下一位置上{dest++;ss.pop();continue;}if (*sour == '\0'&& ss.top() != *dest)  //如果一直不相等,知道入栈序列结束仍为匹配上,说明出栈序列非法{return false;}}return true;<span style="white-space:pre"></span>//否则序列合法}int main(){char *str1 = "abcbd";char *str2 = "abdbc";int ret = judge(str1, str2);cout << ret << endl;return 0;}

注:对于上述代码,只是实现了字符串的类型比较。要接受任意类型的参数,比如浮点型,自定义类型,结构体类型等就可以实现C++中的模板类,以实现代码的复用。

例如:

template<class T>bool judge(const T*sour,const T*dest,size_t size,size_t size)   //注意此时要传入序列的大小,并且创建栈时的类型也须换成T


结语:代码执行流程的顺序图在此就不画了,本人画图工具用的不6,不美观,读者可自行画图帮助理解。






0 0