1、符号就近匹配
就近匹配算法思路:
1、从第一个字符串开始扫描
2、当遇见普通字符串时忽略
3、当遇见左符号时压入桟中
4、当遇见右符号时,从桟中弹出栈顶符号,并进行匹配:
匹配成功:继续读入下一个字符
匹配失败:立即停止,并报错
5、结束:
成功:所有字符扫描完毕,且栈为空
失败:匹配失败或所有字符扫描完毕但栈非空
代码实现:
#include "dm06_LinkStack.h"
bool isLeft(const char c)
{
switch (c)
{
case '{' :
case '<':
case '[':
case '(':
case '\'':
case '\"':
return true; break;
default:
return false; break;
}
}
bool isRight(const char c)
{
switch (c)
{
case '}':
case '>':
case ']':
case ')':
case '\'':
case '\"':
return true; break;
default:
return false; break;
}
}
bool match(const char l, const char r)
{
bool ret = false;
switch (l)
{
case '{': ret = ('}' == r); break;
case '<': ret = ('>' == r); break;
case '[': ret = (']' == r); break;
case '(': ret = (')' == r); break;
case '\'': ret = ('\'' == r); break;
case '\"': ret = ('\"' == r); break;
default:
break;
}
return ret;
}
void scanner(const char* s)
{
LinkStack* stack = LinkStack_Create();
if (nullptr == stack)
{
printf("func scanner() err: nullptr\n");
return;
}
int i = 0;
int ret = 0;
while (s[i] != '\0')
{
if (isLeft(s[i]))
{
ret = LinkStack_Push(stack, (void *)(s + i));
if (0 != ret) {printf("func scanner() err: %d\n", ret); return; }
}
else if (isRight(s[i]))
{
char* lc = (char *)LinkStack_Top(stack);
if (nullptr == lc)
{
printf("failed: %c 缺失对应的左值\n", s[i]);
break;
}
if (isLeft(*lc) && match(*lc, s[i]))
{
LinkStack_Pop(stack);
}
else if (isLeft(*lc) && !match(*lc, s[i]))
{
printf("faild : %c 和 %c 不匹配\n", *lc, s[i]);
break;
}
else
{
printf("faild : 栈顶元素 %c 不是左值\n", *lc);
break;
}
}
i++;
}
if (LinkStack_Size(stack) == 0 && s[i] == '\0')
{
printf("success!\n");
}
else
{
printf("faild : 栈中元素不为空\n");
}
LinkStack_Destory(stack);
return;
}
void main07()
{
const char* code = "#include <stdio.h> int main(){int a[4][4]; int (*p)[4]; p = a[0]; return 0;}";
scanner(code);
cout << "---------------------------" << endl;
system("pause");
return;
}
其中,头文件 dm06_LinkStack.h 请参考资源下载中的《栈的链式存储与实现》资源。链接:https://download.csdn.net/download/bailang_zhizun/12670871。下同。
2、中缀转后缀表达式
中缀转后缀算法思路:
1、遍历中缀表达式中的数字和符号
2、如果是数字,则直接输出
3、对于符号:
左括号:直接进栈
运算符号:与栈顶元素的进行优先级比较
若栈顶符号优先级低: 此运算符号进栈(默认栈顶元素是左括号,左括号优先级最低)
若栈顶符号优先级高: 将栈顶符号弹出并输出,之后进栈
右括号:将栈顶元素弹出并输出,直到匹配左括号(左括号也要弹出不输出)
4、遍历结束:
成功:将桟中所有符号弹出并输出
代码实现:
#include "dm06_LinkStack.h"
//返回true: 是操作符
//返回false: 不是操作符
bool is_operator(const char c)
{
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')')
return true;
return false;
}
//top: 栈顶元素
//c: 需要比较的元素(字符串中的元素)
//返回true: 栈顶元素优先级低 ;
//返回false: 栈顶元素优先级高;
bool priority_compare(const char* top, const char c)
{
bool ret = false;
if (nullptr == top) return true; //此时栈中没有元素,所以返回true
switch (*top)
{
case '+':
case '-': if ('*' == c || '/' == c) ret = true; break;
case '*':
case '/': break;
case '(': ret = true; break;
default: break;
}
return ret;
}
void infix_to_suffix(const char* s)
{
LinkStack* stack = LinkStack_Create();
if (nullptr == stack) return;
int i = 0;
int ret = 0;
while (s[i] != '\0')
{
char cur_c = s[i];
if (!is_operator(cur_c))
{
cout << cur_c << " ";
}
else
{
if ('(' == cur_c)
{
//左括号 '(' 直接进栈
LinkStack_Push(stack, (void *)(s+i));
}
else if (')' == cur_c)
{
//右括号:将栈顶元素弹出并输出,直到匹配左括号(左括号也要弹出不输出)
char tmp = '\0';
while (tmp = *(char *)LinkStack_Pop(stack))
{
if ('(' == tmp) break;
cout << tmp << " ";
}
}
else
{
char* top = (char *)LinkStack_Top(stack);
if ( priority_compare(top, cur_c) )
{
LinkStack_Push(stack, (void *)(s+i));
}
else
{
LinkStack_Pop(stack);
cout << *top << " ";
LinkStack_Push(stack, (void *)(s + i));
}
}
}
i++;
}
while (LinkStack_Size(stack) > 0)
{
cout << *(char *)LinkStack_Pop(stack) << " ";
}
cout << endl;
}
void main08()
{
const char* code1 = "8+(3-1)*5"; //suffix: 831-5*+
const char* code2 = "5+4"; //suffix: 54+
const char* code3 = "1+2*3"; //suffix: 123*+
const char* code4 = "9+(3-1)*5+8/2"; //suffix: 931-5*82/++
infix_to_suffix(code4);
cout << "---------------------------" << endl;
system("pause");
return;
}
3、后缀表达式计算
后缀表达式计算思路:
1、遍历后缀表达式中的数字和符号
2、对于数字,直接进栈
3、对于符号:
从桟中弹出右操作数
从桟中弹出左操作数
根据符号进行计算
将运算结果压入桟中
4、遍历结束:
成功:桟中的唯一数字为计算结果
代码实现:
#include "dm06_LinkStack.h"
//根据不同的操作符号执行不同的操作
template<typename T>
T calclute(T ln, T rn, const char oper)
{
T ret = 0;
switch (oper)
{
case '+': ret = ln + rn; break;
case '-': ret = ln - rn; break;
case '*': ret = ln * rn; break;
case '/': (0 == rn) ? (ret = -1) : (ret = ln / rn); break;
default: ret = -1; break;
}
return ret;
}
//多用函数!!!!!!!!!!!!!!!!!!!!!!!
int int_value(const char c)
{
return c - '0';
}
void calculate_saffix_new(const char* s)
{
LinkStack* stack = LinkStack_Create();
if (nullptr == stack) return;
int i = 0;
int ret = 0;
while (s[i] != '\0')
{
const char tmp = s[i];
if (!is_operator(tmp))
{
//1-1 是数字则直接压入桟中
LinkStack_Push(stack, (void *)int_value(tmp));
}
else
{
int right = (int)LinkStack_Pop(stack);
int left = (int)LinkStack_Pop(stack);
int result = calclute<int>(left, right, tmp);
LinkStack_Push(stack, (void *)result);
}
i++;
}
ret = (int)LinkStack_Pop(stack);
cout << "Result: " << ret << endl;
LinkStack_Destory(stack);
return;
}
void main09()
{
const char* code1 = "54+"; //value: 9
const char* code2 = "123*+"; //value: 7
const char* code3 = "831-5*+"; //value: 18
const char* code4 = "931-5*82/++"; //value: 23
calculate_saffix_new(code4);
cout << "---------------------------" << endl;
system("pause");
return;
}