题目
C语言中算术表达式中的括号只有小括号。编写算法,判断一个表达式中的括号是否正确配对,表达式已经存入字符数组exp[]中,表达式的字符个数为n。
分析
本题可以用栈来解决,下面就来说说为什么要用栈来解决。
给你一个表达式,目测怎么判断括号是否匹配呢?可以这样做,从左往右看这个表达式中的括号,看到一个“(“就记住它(这里可以理解为入栈),如果下一个括号是“)”(这里可以理解为出栈),则划掉这两个括号,一对括号处理完毕继续往后看。如果前边所有的括号都被划掉,而下一个括号却是“)”,则括号一定不匹配,因为“)”之前已经没有括号和它匹配了。如果下一个括号是“(",则暂时不管前一个“(”,先把它放在那里,等后边的“(”处理掉后再来处理它。后边的“("处理掉才能回来处理先前的“(",这里体现了栈的先进后出特点。以后看到的括号要么是“(",要么是“)”,就用前边的方法来处理。如果到最后所有括号都被划掉,则匹配,否则就不匹配。由此可见,一个问题中如果出现诸如这种情况,即在解决问题的过程中出现了一个子问题,但凭现有条件不能解决它,需要记下,等待以后出现可以算决它的条件后再返回来解决。这种问题需要用栈来解决,栈具有记忆的功能,这是栈的FILO特性所延伸出来的一种特性。
注意是顺序栈,这里是用链栈的方式演示了配对括号的过程。
代码
配对的核心代码:
/* 用来比较括号是否正确配对,如果正常配对返回1,否则返回0 */
/* exp[]指的是括号表达式数组,是字符型的;n指的是数组元素个数 */
int match(char exp[],int n){
/* 初始化顺序栈 */
SqStack stack;// 定义一个顺序栈
char x;// 定义一个放出栈元素的变量
initStack(stack);// 调用函数初始化顺序栈
/* 判断表达式的括号是否匹配 */
for(int i=0;i<n;i++){// 循环遍历数组中的每个括号
if(exp[i]=='('){// 判断括号是不是'(',如果是的话
push(stack,exp[i]);// 则压入顺序栈
}
if(exp[i]==')'){// 判断括号是不是')',如果是的话
if(isEmpty(stack)==1){// 如果当前遇到的括号是")",并且栈已空,则不匹配,返回0
return 0;
}else{ // 如果栈不空,则出栈。也就是划掉"()"
pop(stack,x);
}
}
}
/* 循环遍历括号表达式完毕后,对结果进行反馈 */
if(isEmpty(stack)==1){// 如果栈空的话,即所有括号都正确配对,返回1
return 1;
}else{// 如果栈不空,则栈中存在着"(",故未能正确配对,返回0
return 0;
}
}
完整代码如下:
#include <stdio.h>
#define maxSize 20
typedef struct {
char data[maxSize];// 存放栈中元素,maxSize是已经定义好的常量
int top;// 栈顶指针
} SqStack; // 顺序栈类型定义
/* 初始化顺序栈 */
/* &st指的是要操作的顺序栈 */
void initStack(SqStack &st) {
st.top=-1; // 只需将栈顶指针设置为-1,本栈中将top=-1规定为栈空状态
}
/* 判断栈空 */
/* st指的是要进行判空的顺序栈 */
int isEmpty(SqStack st) {
// 栈为空的时候返回1,否则返回0
if(st.top==-1) { // 判空的条件是栈顶指针是否等于-1
return 1;
} else {
return 0;
}
}
/* 判断栈满 */
/* st指的是要进行判满的顺序栈 */
int isFull(SqStack st) {
// 如果栈顶指针等于maxSize-1那么栈满,否则栈空
if(st.top==maxSize-1) { // maxSize是栈中最大元素个数,已经定义
return 1;// 栈满返回1
} else {
return 0;// 栈空返回0
}
}
/* 进栈 */
/* &st指的是要操作的栈;x指的是要进栈的数据 */
int push(SqStack &st,char x) {
/* 进栈首先要判断栈是否栈满,如果满栈则不能进栈 */
if(isFull(st)==1) {
return 0;// 如果栈满返回0,表示不能进栈
} else {
// 注意:++top和top++在这里的作用是一样的,都可以使用,如果是a=++top和a=top++,那么两个a的值是不一样的,最后top的值还是一样
++st.top;// 先移动指针,再进栈
st.data[st.top]=x;
return 1;// 进栈成功返回1
}
}
/* 出栈 */
/* &st指的是要操作的栈;&x指的是要出栈的数据 */
int pop(SqStack &st,char &x) {
/* 出栈之前要判断栈是否为空 */
if(isEmpty(st)==1) {// 1表示栈空,0表示非空
return 0;// 如果栈空,不能出栈,返回0
} else {
x=st.data[st.top];// 先取出元素,再出栈
--st.top;
return 1;// 出栈成功返回1
}
}
/* 打印栈,从左到右表示栈底到栈顶 */
/* stack表示要被打印的栈 */
void printStack(SqStack stack) {
printf("\n");
for(int i=0; i<=stack.top; i++) {// 注意:data[0]表示栈底元素,data[top]表示栈顶元素
printf("%c\t",stack.data[i]);// 打印栈中元素
}
printf("\n");
}
/* 用来比较括号是否正确配对,如果正常配对返回1,否则返回0 */
/* exp[]指的是括号表达式数组,是字符型的;n指的是数组元素个数 */
int match(char exp[],int n){
/* 初始化顺序栈 */
SqStack stack;// 定义一个顺序栈
char x;// 定义一个放出栈元素的变量
initStack(stack);// 调用函数初始化顺序栈
/* 判断表达式的括号是否匹配 */
for(int i=0;i<n;i++){// 循环遍历数组中的每个括号
if(exp[i]=='('){// 判断括号是不是'(',如果是的话
push(stack,exp[i]);// 则压入顺序栈
}
if(exp[i]==')'){// 判断括号是不是')',如果是的话
if(isEmpty(stack)==1){// 如果当前遇到的括号是")",并且栈已空,则不匹配,返回0
return 0;
}else{ // 如果栈不空,则出栈。也就是划掉"()"
pop(stack,x);
}
}
}
/* 循环遍历括号表达式完毕后,对结果进行反馈 */
if(isEmpty(stack)==1){// 如果栈空的话,即所有括号都正确配对,返回1
return 1;
}else{// 如果栈不空,则栈中存在着"(",故未能正确配对,返回0
return 0;
}
}
int main() {
int result;
char exp[]={'(',')','(','(',')'};
result=match(exp,5);
printf("是否匹配(1表示正确配对,0表示错误配对):%d",result);
return 0;
}
测试效果:
简化栈操作的代码:
#include <stdio.h>
#define maxSize 20
/* 用来比较括号是否正确配对,如果正常配对返回1,否则返回0 */
/* exp[]指的是括号表达式数组,是字符型的;n指的是数组元素个数 */
int match(char exp[],int n){
/* 初始化顺序栈,简化操作 */
char stack[maxSize];
int top=-1;
/* 判断表达式的括号是否匹配 */
for(int i=0;i<n;i++){// 循环遍历数组中的每个括号
if(exp[i]=='('){// 判断括号是不是'(',如果是的话
stack[++top]='(';// 入栈
}
if(exp[i]==')'){// 判断括号是不是')',如果是的话
if(top==-1){// 如果当前遇到的括号是")",并且栈已空,则不匹配,返回0
return 0;
}else{ // 如果栈不空,则出栈。也就是划掉"()"
--top;
}
}
}
/* 循环遍历括号表达式完毕后,对结果进行反馈 */
if(top==-1){// 如果栈空的话,即所有括号都正确配对,返回1
return 1;
}else{// 如果栈不空,则栈中存在着"(",故未能正确配对,返回0
return 0;
}
}
int main() {
int result;
char exp[]={'(',')','(','(',')'};
result=match(exp,5);
printf("是否匹配(1表示正确配对,0表示错误配对):%d",result);
return 0;
}