栈的简单应用
我们可以重复利用之前写过的[栈的链式存储](http://blog.csdn.net/strugglingmice/article/details/75195411)中的代码,在此基础上完成栈的一下的一些简单的应用。
(一)就近匹配
**几乎所有的编译器都具有检测括号是否匹配的能力,如何实现编译器中的符号成对检测?**
当需要检测成对出现但又互不相邻的事物,可以使用栈“后进先出”的特,栈非常适合于需要'就近匹配'的场合。
#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0;
算法思路
①从第一个字符开始描;
②当遇见普通字符时忽略,当遇见左符号时压入中;
③当遇见右符号时从栈中弹出栈顶符号,并进行配;
匹配成功:继续读入下一个字符;
匹配失败:立即停止,并报错;
④结束:
成功:所有字符扫描完毕,且栈为空;
失败:匹配失败或所有所有字符扫描完毕但栈非空。
就近匹配的实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkStack.h"
int isLeft(char c)
{
int ret = 0;
switch (c)
{
case '<':
case '(':
case'{':
case'[':
case '\'':
case '\"':
ret = 1;
break;
default:
break;
}
return ret;
}
int isRight(char c)
{
int ret = 0;
switch (c)
{
case '>':
case ')':
case'}':
case']':
case '\'':
case '\"':
ret = 1;
break;
default:
break;
}
return ret;
}
int match(char left, char right)
{
int ret = 0;
switch (left)
{
case '<':
if (right == '>')
{
ret = 1;
}
break;
case '(':
if (right == ')')
{
ret = 1;
}
break;
case '{':
if (right == '}')
{
ret = 1;
}
break;
case '[':
if (right == ']')
{
ret = 1;
}
break;
case '\'':
if (right == '\'')
{
ret = 1;
}
break;
case '\"':
if (right == '\"')
{
ret = 1;
}
break;
default:
break;
}
return ret;
}
int scanner(const char *code)
{
LinkStack *stack = LinkStack_Create();
int ret = 0;
int i = 0;
while (code[i] != '\0')
{
//当遇见普通字符时忽略
if (isLeft(code[i]))
{//当遇见左符号时压入栈中
LinkStack_Push(stack, (LinkStackNode*)(code + i));//&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("Invalide code!\n");
ret = 0;
}
LinkStack_Destroy(stack);
return ret;
}
void main()
{
const char *code = "#include <stdio.h> int main(){int a[4][4], int (*p)[4];p=a[0];return 0;";
scanner(code);
system("pause");
return;
}
结果截图
(二)中缀转后缀
计算机的本质工作就是做数学运算,那计算机可以读入字符串“9 + (3 - 1) * 5 + 8 / 2”并计算值吗?
(1)中缀表达式符合人类的阅读和思维习惯;
(2)后缀表达式符合计算机的”运算习惯”;
(3)如何将中缀表达式转换成后缀表达式?
算法思路
①遍历中缀表达式中的数字和符号;
②对于数字:直接输出;
③对于符号:
左括号:进栈;
运算符:与栈顶运算符号进行优先级比较;若栈顶优先级低,此符号进栈(默认栈顶若是左括号,左括号优先级最低);若是栈顶符号优先级不低,将栈顶符号弹出并输出,之后进栈;
右括号:将栈顶符号弹出,直到匹配左括号;
④遍历结束:将栈中的所有符号弹出并输出。
中缀转后缀的实现
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "linkstack.h"
int isNumber(char c)
{
return ('0' <= c) && (c <= '9');
}
int isOperator(char c)
{
return (c == '+') || (c == '-') || (c == '*') || (c == '/');
}
int isLeft(char c)
{
return (c == '(');
}
int isRight(char c)
{
return (c == ')');
}
int priority(char c)
{
int ret = 0;
if ((c == '+') || (c == '-'))
{
ret = 1;
}
if ((c == '*') || (c == '/'))
{
ret = 2;
}
return ret;
}
void output(char c)
{
if (c != '\0')
{
printf("%c", c);
}
}
void transform(const char* exp)
{
int i = 0;
LinkStack* stack = LinkStack_Create();
while (exp[i] != '\0')
{
if (isNumber(exp[i]))
{
output(exp[i]);
}
else if (isOperator(exp[i]))
{
if (LinkStack_Size(stack)>0)//往栈中插入第一个符号时
{
while (priority(exp[i]) <= priority((char)(int)LinkStack_Top(stack)))
{
output((char)(int)LinkStack_Pop(stack));
}
}
LinkStack_Push(stack, (void*)(int)exp[i]);
}
else if (isLeft(exp[i]))
{
LinkStack_Push(stack, (void*)(int)exp[i]);
}
else if (isRight(exp[i]))
{
//char c = '\0';
while (!isLeft((char)(int)LinkStack_Top(stack)))
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!");
break;
}
i++;
}
while ((LinkStack_Size(stack) > 0) && (exp[i] == '\0'))
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Destroy(stack);
}
int main()
{
transform("8+(3-1)*5");
printf("\n");
system("pause");
return 0;
}
结果截图
(三)后缀表达式的计算
实例
中缀表达式:8+(3-1)﹡5的后缀表达式为:831-5﹡+ 。
算法思路
①对于数字:进栈;
②对于符号: 从栈中弹出右操作数; 从栈中弹出左操作数;根据符号进行运算; 根据符号进行运算;
③遍历结束:栈中的唯一数字为计算结果。
后缀表达式计算的实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkStack.h"
int isNumber(char c)
{
return (('0' <= c) && (c <= '9'));
}
int isOperator(char c)
{
return ((c == '+') || (c == '-') || (c == '*') || (c == '/'));
}
int vlaue(char c)
{
return (c - '0');
}
int express(int left, int right, int op)
{
int ret = 0;
switch (op)
{
case '+':
ret = left + right;
break;
case '-':
ret = left - right;
break;
case '*':
ret = left*right;
break;
case '/':
ret = left / right;
break;
default :
break;
}
return ret;
}
int computer(const char *exp)
{
LinkStack *stack = LinkStack_Create();
int ret = 0;
int i = 0;
while (exp[i] != '\0')
{
if (isNumber(exp[i]))
{
LinkStack_Push(stack, (LinkStackNode *)vlaue(exp[i])); //831-5*+
}
else if (isOperator(exp[i]))
{
int right = (int)LinkStack_Pop(stack);
int left = (int)LinkStack_Pop(stack);
int result = express(left, right, exp[i]);
LinkStack_Push(stack, (LinkStackNode *)result);
}
else
{
printf("Invalid expression!\n");
break;
}
i++;
}
if (LinkStack_Size(stack) == 1 && (exp[i] == '\0'))
{
ret = (int)LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!\n");
}
LinkStack_Destroy(stack);
return ret;
}
int main()
{
printf("8+(3-1)*5=%d\n", computer("831-5*+"));
system("pause");
return 0;
}
结果截图