中缀表达式就是我们平时运算表达式,其特点是运算符总是处于两个运算对象之间。但是该表达式计算机处理起来较为麻烦,会将其转写成后缀表达式,后缀表达式也叫逆波兰表达式
,后缀表达式的特点是每个运算符都置于两个运算对象之后。此篇的部分内容参考博文地址为:C++栈的应用-中缀转后缀。
实例
遍历中缀表达式中的数字和符号:
对于数字:直接输出
对于符号:
遍历结束:将栈中的所有符号弹出并输出
8 + (3 - 1) * 5
的转换过程进行实例分析。前面在C++数据结构X篇_08_C++实现栈的顺序存储与链式存储中讲到了栈中数据先进后出
。
以下是遍历的过程:
(1)遍历到1位置
8
数字直接输出,+
运算符进栈,左括号
进栈,-
进栈
(2)遍历到右括号位置
输出-
,匹配到左括号,将左括号和右括号扔掉
(3)遍历到*
位置
由于*
优先级高于+
,进栈
(4)遍历结束
将栈中的所有符号弹出并输出
下面将会用程序的方法输出该案例,这里栈选用链式存储的栈,具体介绍可见C++实现栈的顺序存储与链式存储。
//有关栈的基本操作
//节点
class linknode
{
public:
linknode* next;
};
//自定义数据
class my_data
{
public:
linknode* node;
char c;
};
//链式栈
class linkstack
{
public:
linknode head;
int size;
};
//初始化栈
linkstack* init_linkstack()
{
linkstack* stack=new linkstack;
stack->head.next=NULL;
stack->size=0;
return stack;
}
//入栈
void push_linkstack(linkstack* stack,linknode* data)
{
data->next=stack->head.next;
stack->head.next=data;
stack->size++;
}
//出栈
void pop_linkstack(linkstack* stack)
{
stack->head.next=stack->head.next->next;
stack->size--;
}
//返回栈顶元素
linknode* top_linkstack(linkstack* stack)
{
return stack->head.next;
}
//判断字符是否为数字
int isnumber(char c)
{
return c>='0' && c<='9';
}
//判断是否为左括号
int isleft(char c)
{
return c=='(';
}
//判断是否为右括号
int isright(char c)
{
return c==')';
}
//判断是否为运算赋
int isoperator(char c)
{
return c=='+' || c=='-' || c=='*' || c=='/';
}
//判断运算符优先级
int getpriority(char c)
{
if (c=='*' || c=='/')
{
return 2;
}
if (c=='+' || c=='-')
{
return 1;
}
if (c=='(' || c==')')
{
return 0;
}
return -1;
}
int main()
{
linkstack* stack = init_linkstack();
char str[] = "8 + (3 - 1) * 5";
for (int i = 0; i < sizeof(str) / sizeof(char); i++) //逐字符遍历str获得操作符;
{
my_data* data = new my_data;
data->node = NULL;
data->c = str[i];
if (isnumber(str[i])) //如果操作符为数字,直接输出
{
cout << str[i] << "\t";
}
if (isleft(str[i])) //如果操作符为左括号,直接进栈
{
push_linkstack(stack, (linknode*)data);
}
if (isright(str[i])) //如果操作符为右括号从栈里往外弹元素直到弹出左括号为止
{
while (stack->size > 0)
{
char* c = &((my_data*)top_linkstack(stack))->c;
if (isleft(*c)) //匹配到左括号弹出
{
pop_linkstack(stack);
break;
}
//匹配到运算符,打印运算符并弹出运算符
cout << *c << "\t";
pop_linkstack(stack);
}
}
//如果操作符是运算符
if (isoperator(str[i]))
{
if (stack->size == 0) //如果栈为空,操作符直接入栈
{
push_linkstack(stack, (linknode*)data);
}
else //不是空栈则需要进行优先级比较
{
while (stack->size > 0) //操作符与栈中元素符号优先级比较
{
char* c = &((my_data*)top_linkstack(stack))->c; //栈顶元素符号
if (getpriority(data->c) > getpriority(*c)) //操作符符优先级高于栈中top元素符号,操作符入栈
{
push_linkstack(stack, (linknode*)data);
break;
}
if (getpriority(data->c) <= getpriority(*c)) //操作符优先级低于或等于栈中top元素符号,并打印并弹出栈中top元素
{
cout << ((my_data*)top_linkstack(stack))->c << "\t";
pop_linkstack(stack);
if (stack->size == 0) //弹出top元素后栈为空,操作符直接入栈
{
push_linkstack(stack, (linknode*)data);
break;
}
}
}
}
}
}
//如果str遍历完了,但栈中还有元素符号,将其逐个输出,直到栈空为止
while (stack->size > 0)
{
cout << ((my_data*)top_linkstack(stack))->c << "\t";
pop_linkstack(stack);
}
cout << endl;
system("pause");
return 0;
}
#include
using namespace std;
// 有关栈的基本操作
//节点
class linknode
{
public:
linknode* next;
};
//自定义数据
class my_data
{
public:
linknode* node;
char c;
};
//链式栈
class linkstack
{
public:
linknode head;
int size;
};
//初始化栈
linkstack* init_linkstack()
{
linkstack* stack = new linkstack;
stack->head.next = NULL;
stack->size = 0;
return stack;
}
//入栈
void push_linkstack(linkstack* stack, linknode* data)
{
data->next = stack->head.next;
stack->head.next = data;
stack->size++;
}
//出栈
void pop_linkstack(linkstack* stack)
{
stack->head.next = stack->head.next->next;
stack->size--;
}
//返回栈顶元素
linknode* top_linkstack(linkstack* stack)
{
return stack->head.next;
}
//判断字符是否为数字
int isnumber(char c)
{
return c >= '0' && c <= '9';
}
//判断是否为左括号
int isleft(char c)
{
return c == '(';
}
//判断是否为右括号
int isright(char c)
{
return c == ')';
}
//判断是否为运算赋
int isoperator(char c)
{
return c == '+' || c == '-' || c == '*' || c == '/';
}
//判断运算符优先级
int getpriority(char c)
{
if (c == '*' || c == '/')
{
return 2;
}
if (c == '+' || c == '-')
{
return 1;
}
if (c == '(' || c == ')')
{
return 0;
}
return -1;
}
int main()
{
linkstack* stack = init_linkstack();
char str[] = "8 + (3 - 1) * 5";
for (int i = 0; i < sizeof(str) / sizeof(char); i++) //逐字符遍历str获得操作符;
{
my_data* data = new my_data;
data->node = NULL;
data->c = str[i];
if (isnumber(str[i])) //如果操作符为数字,直接输出
{
cout << str[i] << "\t";
}
if (isleft(str[i])) //如果操作符为左括号,直接进栈
{
push_linkstack(stack, (linknode*)data);
}
if (isright(str[i])) //如果操作符为右括号从栈里往外弹元素直到弹出左括号为止
{
while (stack->size > 0)
{
char* c = &((my_data*)top_linkstack(stack))->c;
if (isleft(*c)) //匹配到左括号弹出
{
pop_linkstack(stack);
break;
}
//匹配到运算符,打印运算符并弹出运算符
cout << *c << "\t";
pop_linkstack(stack);
}
}
//如果操作符是运算符
if (isoperator(str[i]))
{
if (stack->size == 0) //如果栈为空,操作符直接入栈
{
push_linkstack(stack, (linknode*)data);
}
else //不是空栈则需要进行优先级比较
{
while (stack->size > 0) //操作符与栈中元素符号优先级比较
{
char* c = &((my_data*)top_linkstack(stack))->c; //栈顶元素符号
if (getpriority(data->c) > getpriority(*c)) //操作符符优先级高于栈中top元素符号,操作符入栈
{
push_linkstack(stack, (linknode*)data);
break;
}
if (getpriority(data->c) <= getpriority(*c)) //操作符优先级低于或等于栈中top元素符号,并打印并弹出栈中top元素
{
cout << ((my_data*)top_linkstack(stack))->c << "\t";
pop_linkstack(stack);
if (stack->size == 0) //弹出top元素后栈为空,操作符直接入栈
{
push_linkstack(stack, (linknode*)data);
break;
}
}
}
}
}
}
//如果str遍历完了,但栈中还有元素符号,将其逐个输出,直到栈空为止
while (stack->size > 0)
{
cout << ((my_data*)top_linkstack(stack))->c << "\t";
pop_linkstack(stack);
}
cout << endl;
system("pause");
return 0;
}