1.问题的提出
在C语言或者其他编程语言中,有一些符号是成对匹配出现的,例如各种括号,引号,几乎所有的编译器都具备检测括号是否匹配的能力。
为此,我们就来写一个程序来仿照编译器中的符号成对检测。
2.解决方案
2.1.算法思路
1.从第一个字符开始扫描;
2.当遇见普通字符时忽略,当遇见左符号时压入栈中;
3.当遇见右符号时从栈中弹出栈顶符号;
4.进行匹配:
(1)匹配成功:继续读入下一个字符;
(2)匹配失败:立即停止,并报错。
5.结束:
(1)成功:所有字符扫描完毕,且栈为空;
(2)失败:匹配失败或所有字符扫描完毕但栈非空。
2.2.算法框架
算法框架如下图所示:
3.程序演示
主函数比较简单,
int main(int argc, char *argv[])
{
const char* code = "void f(int a[]) {int (*p)[5]; p = NULL; }";
Scanner(code);
return 0;
}
在Scanner函数中,实现的是算法框架里所提到的,
int Scanner(const char* code)
{
LinkStack* stack = LinkStack_Create();
int ret = 0;
int i;
while(code[i] != '\0') //未读到字符串结尾
{
if (isLeft(code[i]))
{
LinkStack_Push(stack, (void*)(code + i));
}
if (isRight(code[i]))
{
char* c = (char*)LinkStack_Pop(stack);
if ((c == NULL) || !match(*c, code[i]))
{
printf("%c does not match!\n", code[i]);
ret = 0;
break;
}
}
i++;
}
if ((LinkStack_Size(stack) == 0) && (code[i] == '\0'))
{
printf("Succeed!\n");
ret = 1;
}
else
{
printf("Invalid code!\n");
ret = 0;
}
LinkStack_Destroy(stack); //防止内存泄露
return ret;
}
int isLeft(char c)
{
int ret = 0;
switch(c)
{
case '<':
case '[':
case '(':
case '{':
case '\'':
case '\"':
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
int isRight(char c)
{
int ret = 0;
switch(c)
{
case '>':
case ']':
case ')':
case '}':
case '\'':
case '\"':
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
int match(char Left, char Right)
{
int ret = 0;
switch(Left)
{
case '<':
ret = (Right == '>');
break;
case '[':
ret = (Right == ']');
break;
case '(':
ret = (Right == ')');
break;
case '{':
ret = (Right == '}');
break;
case '\'':
ret = (Right == '\'');
break;
case '\"':
ret = (Right == '\"');
break;
default:
ret = 0;
break;
}
return ret;
}
得到的结果为:
若去掉示例程序中最左边的圆括号,则得到的结果:
可以看出右圆括号未匹配成功。
4.总结
当需要检测成对出现但又互不相邻的事物时,可以使用栈的“后进先出”的特性;栈非常适合于需要“就近匹配”的场合。