线性结构 - 栈
栈是一种后进先出的数据结构。栈限定为只能从一端进行插入和删除操作。比如一个小桶,小桶的直径只能放一个小球,我们现在小桶内依次放入2、1、3号小球。假如你现在需要拿出2号小球,那就必须先将3号小球拿出,再拿出1号小球,最后才能将2号小球拿出来。在刚才取小球的过程中,我们最先放进去的小球最后才能拿出来,最后放进去的小球却可以最先拿出来。如下图所示:
图 栈示意图
栈的实现很简单,只需要一个一维数组和一个指向栈顶的变量top就可以了。我们通过top来对栈进行插入和删除操作。
栈中插入元素x:
top++;
a[top] = x;
栈中删除元素:
top--;
栈有哪些作用呢?我们看一个例子。“xyzyx”是一个回文字符串,所谓回文字符串就是指正读反读均相同的字符序列,如“aha”,“席主席”等均为回文,但“ahah”就不是回文。我们通过栈这个数据结构判断一个字符串是否为回文。
首先是读取这行字符串,并求出这个字符串的长度:
string s;
int len;
cin >> s;
len = s.size();
如果一个字符串是回文的话,那么它必须是中间对称的,我们需要求出中点,即:
mid = len/2 - 1;
接下来就轮到栈登场了。
我们先将mid之前的字符全部入栈。因为这里的栈是用来存储字符的,所以这里实现栈的数组类型是字符串s。初始化栈很容易: top=0;
下面我们就将mid之前的字符全部入栈:
for(i=0; i<=mid; i++){
s[++top] = a[i];
}
接下来进入判断回文的关键步骤。将当前栈中的字符依次出栈,看看是否能与mid之后的字符一一匹配,如果都能匹配就是回文字符串,否则就不是回文字符串。
for(i=mid+1; i<=len-1; i++){
if (a[i]!=s[top]) break;
top--
}
if (top==0) cout << "YES\n";
else cout << "NO\n";
最后如果top的值为0,说明栈内所有的字符都被一一匹配了,那么这个字符串就是回文字符串。
【程序1】回文字符串 (用栈实现)
输入一个字符串(长度≤10^5),判断是不是回文字符串。如果是回文字符串,输出“yes”,否则输出 “no”。
【样例输入】121
【样例输出】yes
整个代码实现如下:
#include <iostream>
using namespace std;
int main(){
string s;
char a[1001];
cin >> s; //读入一行字符串
int len = s.size(); //求字符串的长度
int mid = len/2-1; //求字符串的中点
int top = 0, next;
for(int i=0; i<=mid; i++) a[++top] = s[i]; //将mid前的字符依次入栈
//判断字符串的长度为奇数还是偶数,并找出需要进行匹配的初始下标
if(len%2==0) next = mid+1;
else next = mid+2;
for(int i=next; i<=len-1; i++){ //开始匹配
if(s[i]!=a[top]) break;
top--;
}
if(top==0) cout << "yes"; else cout << "no";
return 0;
}
【程序2】括号匹配
给定一个算术表达式,检查其中的圆括号是否配对,给出适当信息(正好:Yes,左括号多:Left,右括号多:Right)。如果有多处不配对的情况,给出最早发生不配对时候的信息,例如:表达式())(,最早发生的不配对是在第三个字符())处,故输出Right。
【样例输入】3*(4-5)+9/2
【样例输出】Yes
整个代码实现如下:
#include <iostream>
using namespace std;
int main(){
string s;
cin >> s;
int top=0;
for(int i=0; i<=s.size(); i++){
if (s[i]=='(') top++; //如果是左括号,进栈
if (s[i]==')') top--; //如果是右括号,出栈
if (top<0) break;
}
if (top==0) cout << "Yes\n";
else if (top>0) cout << "Left\n";
else cout << "Right\n";
return 0;
}