题目要求:
假设表达式中允许包含两种括号:圆括号和方括号,其嵌套的顺序随意,即([]())或[([][])]等为正确的格式,[(])或([())或(()])均为不正确的格式。检验括号是否匹配的方法可用“期待的急迫程度”这个概念来描述。例如考虑下列括号序列:
[([][])]
12345678
当计算机接受了第一个括号后,它期待着与其匹配的第八个括号的出现,然而等来的却是
第二个括号,此时第一个括号“[”只能暂时靠边,而迫切等待与第二个括号相匹配的、第七个括号“)”的出现,类似地,因等来的是第三个括号“[”,其期待匹配的程度较第二个括
号更急迫,则第二个括号也只能靠边,让位于第三个括号,显然第二个括号的期待急迫性
高于第一个括号;在接受了第四个括号之后,第三个括号的期待得到满足,消解之后,第二个括号的期待匹配就成为当前最急迫的任务了,……,依次类推。可见,这个处理过程恰与栈的特点相吻合。由此,在算法中设置一个栈,每读入一个括号,若是右括号,则或者使置于栈顶的最急迫的期待得以消解,或者是不合法的情况;若是左括号,则作为一个新的更急迫的期待压入栈中,自然使原有的在栈中的所有未消解的期待的急迫性都降了一级。另外,在算法的开始和结束时,栈都应该是空的。
要求:要求:
(1) 程序要添加适当的注释,程序的书写要采用缩进格式。
(2) 程序要具在一定的健壮性,即当栈满入栈时,程序给出栈满的提示。
(3) 程序要做到界面友好,在程序运行时用户可以根据相应的提示信息进行操作。
//-----!链栈实现括号匹配--------
#include<iostream>
using namespace std;
#define OK 1//定义常量
#define ERROR 0//定义常量
#define OVERFLOW -2//定义常量
typedef char SElemType;//定义类型别名,SELemType表示栈中元素的类型
typedef int Status; //定义函数别名,Status表示函数的返回值类型
typedef struct SNode{
int data;
struct SNode *next;
}SNode,*LinkStack;//将 struct SNode 定义的结构体类型命名为 SNode
//并通过 *LinkStack 这样的语法将该结构体类型的指针命名为 LinkStack
//在后续的代码中,可以直接使用 LinkStack 来声明链栈变量或参数
//实现了初始化栈的函数InitStack,将链栈指针置为空
Status InitStack(LinkStack &S){
S=NULL;
return OK;
}
//判断栈是否为空的函数StackEmpty,通过判断链栈指针是否为空来确定栈是否为空
bool StackEmpty(LinkStack S){
if(!S)
return true;
return false;
}
//入栈操作的函数Push,创建一个新节点并将元素压入栈顶
/*
Status:int类型(前面定义过的)
LinkStack引用数据类型(前面定义过的) SElemType:char类型(前面定义过的)
Status Push(LinkStack &S, SElemType e): 这是函数的声明,说明了该函数名为 Push,
接受一个指向 LinkStack 的引用类型参数 S,和一个 SElemType 类型的参数 e,
返回一个 Status 类型的值
*/
Status Push(LinkStack &S,SElemType e){
SNode *p = new SNode;//创建了一个新的结点指针 p,用 new 运算符动态分配内存来创建一个 SNode 结构体对象,并将其地址赋给 p
if(!p) {
return OVERFLOW;//如果p是空指针,则返回溢出错误码OVERFLOW
}
p->data=e;//将传入的参数 e 的值赋给 p 所指向的结点的 data 成员,即将要入栈的元素值存储在链栈结点中。
p->next=S;// 将链栈中当前的栈顶指针 S 赋给 p 所指向的结点的 next 成员,使新结点 p 的 next 指针指向当前的栈顶结点
S=p;//将链栈的栈顶指针 S 指向新的入栈结点 p,将新结点作为链栈的新的栈顶
return OK;//返回操作成功状态码 OK,表示入栈操作执行成功
}
//出栈操作的函数Pop,将栈顶元素弹出,并释放对应的节点空间
Status Pop(LinkStack &S,SElemType &e){//LinkStack引用数据类型;SElemType:char的别名,以及引用参数e
SNode *p;//创建了一个新的指针变量p,用于临时保存栈顶结点的位置
if(!S)
return ERROR;
e=S->data;//如果栈S不为空,则将栈顶节点的数据data赋值给e,以便在函数外部可以获取到出栈的元素
p=S;//将指针变量p指向栈顶节点即S
S=S->next;//更新栈顶指针S,使其指向下一个节点,实现出栈的操作
delete p;//释放指针变量p所指向的节点的内存空间
return OK;//并返回OK表示出栈成功
}
//获取栈顶元素的函数GetTop:如果栈不为空,则将栈顶元素赋值给参数e
Status GetTop(LinkStack &S,SElemType &e){
if(!S)
return ERROR;//如果S为空则返回ERROR 表示获取栈顶元素失败
e=S->data;
return OK;
}
//核心的函数Matching,用于检验表达式中所含括号是否正确匹配。该函数接受一个链栈作为参数
//算法3.9 括号的匹配
Status Matching(LinkStack S){
//检验表达式中所含括号是否正确匹配,如果匹配,则返回true,否则返回false。
//表达式以“#”结束
InitStack(S);//自定义函数:实现了初始化栈的函数InitStack,将链栈指针置为空
int flag = 1;//标记查找结果以控制循环及返回结果
char c;
SElemType x;
cin >> c;//读入第一个字符
while(c!='#'&&flag){
switch(c){
case '[':
case '('://若是左括号,则将其压入栈
Push(S,c);//自定义函数:入栈操作的函数Push,创建一个新节点并将元素压入栈顶
break;//若当前字符c为左括号“[”或“(”,则将其压入栈S。
case ')'://若当前字符c是右括号")",则根据当前栈顶元素的值分情况考虑
GetTop(S,x);
if(!StackEmpty(S)&&x=='(')//若栈非空且栈顶元素是"(",则匹配成功
Pop(S,x);//出栈操作的函数Pop,将栈顶元素弹出,并释放对应的节点空间
else
flag=0;//若栈空或栈顶元素不是"(" ,则非法
break;
case ']'://若是右括号"]",则根据当前栈元素的值分情况考虑
GetTop(S,x);//获取栈顶元素的函数GetTop:如果栈不为空,则将栈顶元素赋值给参数e
if(!StackEmpty(S)&&x=='[')//若栈顶元素是'[',则匹配成功,//通过判断链栈指针是否为空来确定栈是否为空
Pop(S,x);出栈操作
else
flag=0;
break;
}//switch
cin >> c;//继续读入下一个字符
} //while
if(StackEmpty(S)&&flag) return 1;
else return 0;
} //Matching
//主函数
int main(){
LinkStack S; //直接使用 LinkStack 来声明链栈变量或参数
cout << "请输入待匹配的表达式,以 “# ”结束" << endl;
int flag = (int)Matching(S);
if(flag)
cout << "括号匹配成功!" << endl;
else
cout << "括号匹配失败!" <<endl;
return 0;
}
记一次敲代码过程!
over!