关于栈结构的一个简单练习是:给定入栈的字符序列,判断当前序列能否由初始序列通过一系列的进栈出栈操作得到。下面通过展示两道这种类型的题目来总结一下这种问题处理的思路。
在大方向上,我们应该都是通过基础的栈的进栈出栈操作来模拟生成目标串的过程,判断在过程中有没有不合逻辑之处 。但是在具体实现上可以用多种写法,比如可以以原串为主,也可以以当前串为主来进行循环。
第一题我用了链栈来实现。
问题 给定一个字符串,如s = "abc",通过逐个字符入栈和出栈可以得到另一个串。例如,'a'入栈,'b'入栈,再出栈,'c'入栈,再出栈,出栈,可以得到字符串"bca"。 但是,无论如何无法得到字符串"cab",因为若'c'先出栈,那么'a'和'b'必然都在栈中,而且当前栈顶为'b',因此无法得到"cab"。 给定一个串s,另外若干s的重组,请判断哪些字符串可以通过栈重组得到。 测试输入用例 第一行是一个正整数数n,第二行是一个字符串s,表示s的长度为n。 第三行是一个正整数m, 接下来是s的m个重组串,每个串占一行。 测试输出用例 对于m个重组串中每个串t,每一行按照下列格式输出t是否可以由s通过一个栈重组得到: s->t:k 其中k为1(表示可以通过栈重组得到)或者0(表示不可以通过栈重组得到) 输入样例 3 abc 3 abc bac cab 输出样例 abc->abc:1 abc->bac:1 abc->cab:0
用i,j两个指针分别从头扫描原串和当前串,对于当前串的当前位s1[j],欲使其出现在出栈序列中,就必须先将这一位字符压进栈中。在原始串中寻找这个字符,那么在它之前出现的就必须全部依次被压入栈中。扫描到原串的最后一位之后,就只能将栈里的所有剩余字符依次出栈。在这整个扫描过程中一旦判错则直接返回0

1 /*len是串的长度,s0,s1分别为原串和当前串 */ 2 int OK(int len,char *s0,char *s1){ 3 int i,j;//i为指向原串s0,j为指向要判断的串s1的箭头 4 i=0;j=0; 5 Stack *S=(Stack*)malloc(sizeof(Stack));//不带头结点 6 //s0的最后一位进栈之前 7 while (i<len){ 8 if (s0[i]!=s1[j]){ 9 push(&S,s0[i]); 10 i++; 11 } 12 else{ 13 i++;j++; 14 while ((!isEmpty(S))&&S->c==s1[j]){//找到之后还不要忘了前面的是不是可以出栈 15 j++; 16 pop(&S); 17 } 18 } 19 if (j==len) return 1; 20 } 21 //s0的最后一位进栈之后,就只能倒着检索直接判断 22 while (j<len){ 23 if (s1[j]!=S->c) return 0; 24 pop(&S); 25 j++; 26 } 27 return 1; 28 }
另外一道题目的特点是对栈的大小做了限制,此题我用了数组来模拟栈,更方便统计栈内元素个数。
02-线性结构4 Pop Sequence (25分) (来源:PTA平台) Given a stack which can keep M numbers at most. Push N numbers in the order of 1, 2, 3, ..., N and pop randomly.
You are supposed to tell if a given sequence of numbers is a possible pop sequence of the stack. For example, if M is 5 and N is 7,
we can obtain 1, 2, 3, 4, 5, 6, 7 from the stack, but not 3, 2, 1, 7, 5, 6, 4. Input Specification: Each input file contains one test case. For each case, the first line contains 3 numbers (all no more than 1000):
M (the maximum capacity of the stack), N (the length of push sequence), and K (the number of pop sequences to be checked).
Then K lines follow, each contains a pop sequence of N numbers. All the numbers in a line are separated by a space. Output Specification: For each pop sequence, print in one line "YES" if it is indeed a possible pop sequence of the stack, or "NO" if not. Sample Input: 5 7 5 1 2 3 4 5 6 7 3 2 1 7 5 6 4 7 6 5 4 3 2 1 5 6 4 3 7 2 1 1 7 6 5 4 3 2 Sample Output: YES NO NO YES NO
如果说上一种写法是从原串入栈的角度来把原串的指示变量作为循环的主要关注点,那么这道题目因为“原串”是一个默认的概念,不必专门存储,就在循环过程中主要关注了“当前串”。但是两种写法的宗旨是不变的,都是利用栈来模拟储存,关注过程中是否发生逻辑错误。

1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #define MAXSIZE 1020 5 #define MAXN 1020 6 7 bool OK(int n,int seq[],int size){ 8 int stack[MAXSIZE]; 9 memset(stack,0,sizeof(stack)); 10 bool In_stack[MAXN]; 11 memset(In_stack,0,sizeof(In_stack)); 12 int top=0; 13 for (int i=1;i<=n;i++){ 14 if (In_stack[seq[i]]){ 15 if (stack[top]!=seq[i]) return 0; 16 top--; 17 continue; 18 } 19 for (int j=1;j<=seq[i];j++){ 20 if (!In_stack[j]){ 21 stack[++top]=j; 22 In_stack[j]=1; 23 if (top>size) return 0; 24 } 25 } 26 top--;//当前出栈 27 } 28 return 1; 29 } 30 31 int main(){ 32 int Size,n,t; 33 int seq[MAXN]; 34 scanf("%d%d%d",&Size,&n,&t); 35 while (t){ 36 t--; 37 for (int i=1;i<=n;i++) scanf("%d",&seq[i]); 38 printf("%s",OK(n,seq,Size)?"YES":"NO"); 39 if (t) puts(""); 40 } 41 return 0; 42 }