就近匹配: 应用1:就近匹配 几乎所有的编译器都具有检测括号是否匹配的能力 如何实现编译器中的符号成对检测? #include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0; 算法思路 从第一个字符开始扫描 当遇见普通字符时忽略, 当遇见左符号时压入栈中 当遇见右符号时从栈中弹出栈顶符号,并进行匹配 匹配成功:继续读入下一个字符 匹配失败:立即停止,并报错 结束: 成功: 所有字符扫描完毕,且栈为空 失败:匹配失败或所有字符扫描完毕但栈非空 当需要检测成对出现但又互不相邻的事物时 可以使用栈“后进先出”的特性 栈非常适合于需要“就近匹配”的场合 计算机的本质工作就是做数学运算,那计算机可以读入字符串 “9 + (3 - 1) * 5 + 8 / 2”并计算值吗? #include "stdio.h" #include "stdlib.h" #include "linkstack.h" 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; } 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, (void*)(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("Invalid 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 ; }
中缀表达式和后缀表达式 应用2:中缀 后缀 计算机的本质工作就是做数学运算,那计算机可以读入字符串 “9 + (3 - 1) * 5 + 8 / 2”并计算值吗? 后缀表达式 ==?符合计算机运算 波兰科学家在20世纪50年代提出了一种将运算符放在数字后面的后缀表达式对应的, 我们习惯的数学表达式叫做中缀表达式===》符合人类思考习惯 实例: 5 + 4=> 5 4 + 1 + 2 * 3 => 1 2 3 * + 8 + ( 3 – 1 ) * 5 => 8 3 1 – 5 * + 中缀表达式符合人类的阅读和思维习惯 后缀表达式符合计算机的“运算习惯” 如何将中缀表达式转换成后缀表达式? 中缀转后缀算法: 遍历中缀表达式中的数字和符号 对于数字:直接输出 对于符号: 左括号:进栈 运算符号:与栈顶符号进行优先级比较 若栈顶符号优先级低:此符合进栈 (默认栈顶若是左括号,左括号优先级最低) 若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈 右括号:将栈顶符号弹出并输出,直到匹配左括号 遍历结束:将栈中的所有符号弹出并输出 中缀转后缀 计算机是如何基于后缀表达式计算的? 8 3 1 – 5 * + 遍历后缀表达式中的数字和符号 对于数字:进栈 对于符号: 从栈中弹出右操作数 从栈中弹出左操作数 根据符号进行运算 将运算结果压入栈中 遍历结束:栈中的唯一数字为计算结果 栈的神奇! 中缀表达式是人习惯的表达方式 后缀表达式是计算机喜欢的表达方式 通过栈可以方便的将中缀形式变换为后缀形式 中缀表达式的计算过程类似程序编译运行的过程 扩展:给你一个字符串,计算结果 “1 + 2 * (66 / (2 * 3) + 7 )” 1 字符串解析 词法语法分析 优先级分析 数据结构选型===》栈还是树? #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]) ) { 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; } #include <stdio.h> #include "LinkStack.h" int isNumber3(char c) { return (‘0‘ <= c) && (c <= ‘9‘); } int isOperator3(char c) { return (c == ‘+‘) || (c == ‘-‘) || (c == ‘*‘) || (c == ‘/‘); } int value(char c) { return (c - ‘0‘); } int express(int left, int right, char 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 compute(const char* exp) { LinkStack* stack = LinkStack_Create(); int ret = 0; int i = 0; while( exp[i] != ‘\0‘ ) { if( isNumber3(exp[i]) ) { LinkStack_Push(stack, (void*)value(exp[i])); } else if( isOperator3(exp[i]) ) { int right = (int)LinkStack_Pop(stack); int left = (int)LinkStack_Pop(stack); int result = express(left, right, exp[i]); LinkStack_Push(stack, (void*)result); } else { printf("Invalid expression!"); break; } i++; } if( (LinkStack_Size(stack) == 1) && (exp[i] == ‘\0‘) ) { ret = (int)LinkStack_Pop(stack); } else { printf("Invalid expression!"); } LinkStack_Destroy(stack); return ret; } int main() { printf("8 + (3 - 1) * 5 = %d\n", compute("831-5*+")); system("pause"); return 0; }
时间: 2024-10-06 15:02:17