这是一个栈的使用的例子:四则运算表达式求值时中缀表达式转后缀(逆波兰)表达式,包含括号平衡判断。
转换的规则:
从左到右依次遍历中缀表达式中的数字和符号,若遇到数字则直接输出到后缀表达式;若遇到符号,则将其与栈顶符号进行优先级比较,如果是右括号或者优先级不高于栈顶符号,则栈顶元素依次出栈,并将当前符号进栈,循环处理,直到将中缀表达式遍历完成。
源代码目录结构
直接贴代码:
头文件:Stack.h
#ifndef STACK_H
#define STACK_H
/*定义状态码*/
#define ERROR -1
#define TRUE 1
#define FALSE 0
typedef int Status;
/*定义结构体*/
#define MAXSIZE 100
typedef char ElemType;
typedef struct
{
ElemType data[MAXSIZE];
int top;
}Stack , *PtrStack;
/*函数原型说明*/
PtrStack InitStack ();
Status IsEmpty(Stack *s);
Status Push (Stack *s , ElemType e);
Status Pop (Stack *s , ElemType *e);
int ExpMidToLast(char *midExp , char *postExp);
int IsExpBalance (char *midExp);
#endif
主函数所在,EX_Stack.c
#include "Stack.h"
#include<stdio.h>
void inputMidExp(char *midExp);
void outputPostExp(char *postExp);
void main ()
{
int i = 0;
char c;
char midExp[100] , postExp[100];
inputMidExp(midExp);
if(IsExpBalance (midExp) == 1)
{
printf("表达式中括号平衡\n");
if (ExpMidToLast (midExp , postExp) == -1)
{
printf("ERROR");
}
else
{
outputPostExp(postExp);
}
}
else
{
printf("表达式括号不平衡\n");
}
}
void inputMidExp(char *midExp)
{
char c;
int i = 0;
printf("请输入四则运算表达式:\n");
scanf("%c" , &c);
while (c != '\n')
{
midExp[i++] = c;
scanf("%c" , &c);
}
midExp[i] = '\0';
}
void outputPostExp(char *postExp)
{
int i = 0;
printf("逆波兰表达式:\n");
while (postExp[i] != '\0')
{
printf("%c" , postExp[i]);
i++;
}
printf("\n");
}
判断中缀表达式是否括号平衡,IsExpBalance.c
若表达式中有诸如<>[]等,也是一样处理,这里只是举例说明
#include "Stack.h"
#include<stdio.h>
int IsExpBalance (char *midExp)
{
int i = 0;
ElemType e;
PtrStack s;
s = InitStack();
if (!s)
{
return -1;
}
while (midExp[i] != '\0')
{
switch(midExp[i])
{
case '(':
Push(s , midExp[i]);
break;
case ')':
if (IsEmpty(s))
{
return 0;
}
Pop(s , &e);
break;
default :
break;
}
i++;
}
if(IsEmpty(s))
{
return 1;
}
else
{
return 0;
}
}
栈的基本操作的实现,StackOperation.c
包括初始化、判断是否为空、入栈、出栈,
#include "Stack.h"
#include<stdio.h>
#include<stdlib.h>
PtrStack InitStack()
{
PtrStack s;
s = (PtrStack)malloc(sizeof(Stack));
if (s != NULL)
{
s ->top = -1;
}
return s;
}
Status IsEmpty (Stack *s)
{
if (s->top == -1)
{
return TRUE;
}
return FALSE;
}
Status Push (Stack *s , ElemType e)
{
if (s->top == MAXSIZE - 1)
{
return ERROR;
}
s->data[++s->top] = e;
return TRUE;
}
Status Pop (Stack *s , ElemType *e)
{
if (s->top == -1)
{
return ERROR;
}
*e = s->data[s->top];
s->top --;
return TRUE;
}
中缀表达式转后缀表达式核心代码,MidToPost.c
#include "Stack.h"
#include<stdio.h>
int ExpMidToLast (char *midExp , char *postExp)
{
int i , j;
char elem , temp;
ElemType e;
PtrStack s;
s = InitStack();
if (!s)
{
return -1;
}
i = j = 0;
elem = midExp[i];
while (elem != '\0')
{
switch (elem)
{
case '(':
{
Push(s , elem);
break ;
}
case ')':
{
postExp[j++] = ' ';
Pop(s , &e);
temp = e;
/*只要不是左括号,则全部弹出*/
while('(' != temp)
{
postExp[j++] = temp;
Pop(s , &e);
temp = e;
}
break;
}
case '*':
case '/':
{
postExp[j++] = ' ';
if ( !IsEmpty(s) )
{
Pop(s , &e);
temp = e;
while(temp != '+' && temp != '-' && temp != '(')
{
postExp[j++] = temp;
postExp[j++] = ' ';
if(IsEmpty(s))
{
break;
}
Pop(s , &e);
temp = e;
}
Push(s , temp);
}
Push(s , elem);
break;
}
case '-':
case '+':
{
postExp[j++] = ' ';
if(!IsEmpty(s))
{
/*弹出所有非左括号的操作符*/
Pop(s , &e);
temp = e;
while('(' != temp )
{
postExp[j++] = temp;
postExp[j++] = ' ';
if(IsEmpty(s))
{
break;
}
Pop(s , &e);
temp = e;
}
if('(' == temp)
{
Push(s , temp);
}
}
Push(s , elem);
break;
}
default:
{
/*数字直接输出到后缀表达式*/
postExp[j++] = elem;
break;
}
}
elem = midExp[++i];
}
/*将栈中非空的操作符输出到后缀表达式中*/
while(!IsEmpty(s))
{
Pop(s , &e);
temp = e;
postExp[j++] = ' ';
postExp[j++] = e;
}
postExp[j] = '\0';
return 1;
}
结果
最后补充两点:
1、根据后缀(逆波兰)表达式求值更简单,规则为:从左到右依次遍历后缀表达式,遇到数字就进栈(这里要注意数字的转化处理,根据分隔符-空格判断),遇到符号就将处于栈顶的两个数字出栈进行运算之后将结果进栈,直到遍历结束即可得到表达式的运算结果。这里就不写代码出来了。
2、关于初始输入的中缀表达式的格式的判断问题,我现在只能想到最拙劣的办法,就是遍历表达式,然后去判断每个字符前后的字符是否符合规则,比如‘+’前一个字符不能是运算符和‘(’,后一个字符不能是运算符和‘)’,并且不能位于表达式的第一个位置。大家如果有什么好办法可以留言交流。
:)