以下では、スタックを使用して逆ポーランド計算機を実装し、ユーザーが入力した中置式を接尾式に変換してから、結果を計算します。
2つのチェーンスタックが使用され、1つのスタックの要素は文字タイプであり、ユーザーが入力したデータを処理するために使用され、サフィックス式に変換され、文字配列に格納され、別のスタックが使用され、スタック内の要素は整数です。入力し、スタックを使用してサフィックス式を処理してから出力します。
PS。実行できるのは整数演算のみです。小数を扱う場合は、接尾辞の式を処理するスタック内の要素タイプを浮動小数点または倍精度浮動小数点型に変更し、小数点を処理する必要があります。
アルゴリズムの手順:ステップ1:
中置式を後置式に変換する中置式の
各オブジェクトを最初から最後まで読み取り
ます。各オブジェクトを処理します。1.オペランド:直接出力
2.左括弧:内スタック
3.右括弧:スタックの最上部で演算子をポップし、左括弧が出現するまでそれを出力します(スタック外、出力ではありません)
。4.演算子:(優先度:括弧>乗算と除算>加算と減算)
優先度がスタックより大きい場合最上位の演算子がスタックに置かれます。
優先順位が最上位の演算子以下の場合、最上位の演算子がポップされて出力され、演算子が最上位の演算子の優先順位より大きくなるまで、新しい最上位の演算子が比較されます。演算子はスタックにプッシュされます(要するに、プラス記号とマイナス記号を読み取ると、スタックが空になるか、ポップアウトが左括弧になるまでポップされ、次に、プラス記号とマイナス記号がスタックにプッシュされます。乗算記号と除算記号を読み取ると、スタックに直接移動します)
。5.オブジェクト処理が完了すると、スタック出力のすべての演算子が出力されます。
ステップ2:サフィックス式を計算します
。1.中置式の各数値と記号を左から右にトラバースします
。2.数値の
場合はスタックにプッシュされます。3 .記号の場合はスタックに配置されます。計算し、上位2つの数値をポップ
4.計算結果を スタック
スタックの最終結果及び最終結果まで5
コードは次のとおりです。
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<windows.h>
#define STACK_H_INCLUDED
#define DATASIZE 50//存放后缀表达式的数组长度
#define MAXBUFFER 10//最大缓冲区大小
typedef char ElemType;
typedef int elemtype;
typedef enum Status
{
error,
success
} Status;
typedef struct StackNode
{
ElemType data;
struct StackNode *next;
}StackNode, *LinkStackPtr;
typedef struct LinkStack
{
LinkStackPtr top;
int count;
}LinkStack;
typedef struct stacknode
{
elemtype data;
struct stacknode *next;
}stacknode, *linkstackptr;
typedef struct linkstack
{
linkstackptr top;
int count;
}linkstack;
//函数的声明(链栈)
//栈内元素为字符型,用于处理输入的数据
Status initLStack(LinkStack *s);//初始化栈
Status notEmptyLStack(LinkStack *s);//判断栈是否为空
void Push(LinkStack *s,ElemType data);//入栈
void Pop(LinkStack *s,ElemType *data);//出栈
//栈内元素为整型,用于处理输出的数据
Status initlstack(linkstack *s);//初始化栈
void push(linkstack *s,elemtype data);//入栈
void pop(linkstack *s,elemtype *data);//出栈
//下面是字符型链栈基本操作的函数
Status initLStack(LinkStack *s)
{
s->top = NULL;
s->count = 0;
return success;
}
Status notEmptyLStack(LinkStack *s)
{
if(s->top != NULL)//非空返回1
{
return success;
}
else
{
return error;
}
}
void Push(LinkStack *s,ElemType data)
{
LinkStackPtr new = (LinkStackPtr)malloc(sizeof(StackNode));
if(new == NULL)
{
printf("内存分配失败\n");
system("pause");
exit(0);
}
new->data = data;
new->next = s->top;
s->top = new;
s->count++;
}
void Pop(LinkStack *s,ElemType *data)
{
if(s->top == NULL)
{
printf("栈空\n");
system("pause");
exit(0);
}
else
{
LinkStackPtr temp;
*data = s->top->data;
temp = s->top;
s->top = s->top->next;
free(temp);
s->count--;
}
}
//下面是整型链栈基本操作的函数
Status initlstack(linkstack *s)
{
s->top = NULL;
s->count = 0;
return success;
}
void push(linkstack *s,elemtype data)
{
linkstackptr new = (linkstackptr)malloc(sizeof(stacknode));
if(new == NULL)
{
printf("内存分配失败\n");
system("pause");
exit(0);
}
new->data = data;
new->next = s->top;
s->top = new;
s->count++;
}
void pop(linkstack *s,elemtype *data)
{
if(s->top == NULL)//栈空,对应错误:如用户输入:1+=
{
printf("\n出错:输入格式错误!\n");
printf("请切换成英文,匹配好括号或者不要输入空格等等\n");
system("pause");
exit(0);
}
else
{
linkstackptr temp;
*data = s->top->data;
temp = s->top;
s->top = s->top->next;
free(temp);
s->count--;
}
}
int main(void)
{
//共用变量
int i = 0;//数组下标
//中缀表达式转换后缀表达式的变量
LinkStack s;
char c, d;//处理输入的数据
char data[DATASIZE];//存放后缀表达式
//计算后缀表达式的变量
linkstack s1;
char str[MAXBUFFER];//缓冲区,用于处理连续的数字
elemtype n1, n2;//处理输出的数据
int n = 0;//缓冲区内计数器
//初始化两个栈
if(!initLStack(&s))
{
printf("初始化失败\n");
system("pause");
return -1;
}
if(!initlstack(&s1))
{
printf("初始化失败\n");
system("pause");
return -1;
}
//下面将中缀表达式转换为后缀表达式储存在数组data中
printf("请输入中缀表达式,以=作为结束标志(只能进行整数运算):");
scanf("%c", &c);
while( c != '=' )//一直接收用户输入,直到读取到=为止
{
while(c>='0' && c<='9')//整数直接存入数组
{
data[i] = c;
i++;
scanf("%c", &c);
if(c<'0' || c>'9')//处理连续的数字
{
data[i] = ' ';
i++;
}
}
if(c == ')')
{
Pop(&s, &d);//出栈
while(d != '(')//不是左括号就存入数组
{
data[i] = d;
i++;
Pop(&s, &d);
}
}
else if(c == '+' || c == '-')
{
if(!notEmptyLStack(&s))//栈空即入栈
{
Push(&s, c);
}
else//栈非空则比较栈顶元素
{
do
{
Pop(&s, &d);
if(d == '(')
{
Push(&s, d);
}
else//不是左括号就存入数组
{
data[i] = d;
i++;
}
}while(notEmptyLStack(&s) && d != '(');
//直到栈空或者读取到左括号
Push(&s, c);//然后再入栈
}
}
else if(c == '(' || c == '*' || c == '/')
{
Push(&s, c);
}
else if(c == '=')
{
break;
}
else
{
printf("\n出错:输入格式错误!\n");
printf("请切换成英文,匹配好括号或者不要输入空格等等\n");
system("pause");
return -1;
}
scanf("%c", &c);
}
//检查如果=前无运算符,eg:1=
if(!notEmptyLStack(&s))
{
printf("\n出错:输入格式错误!\n");
printf("请切换成英文,匹配好括号或者不要输入空格等等\n");
system("pause");
return -1;
}
while(notEmptyLStack(&s))//将栈内剩余对象存放到数组
{
Pop(&s, &data[i]);
i++;
data[i] = '=';
data[i+1] = '\0';//字符串结束标志
}
printf("\n后缀表达式:\n");
printf("%s\n", data);
//下面计算后缀表达式
for(i = 0; data[i] != '\0'; i++)
{
//下面对数字进行处理
while(isdigit(data[i]))
{
str[n++] = data[i];
str[n] = '\0';//字符串结束
if(n >= MAXBUFFER)
{
printf("输入的单个数据过大\n");
system("pause");
return -1;
}
i++;
if(data[i] == ' ')//读取到空格时对前面的所有数字进行处理
{
n1 = atoi(str);//将字符串转换成整型数据
push(&s1, n1);
n = 0;//计数器重新初始化
break;
}
}
switch(data[i])//过滤掉数字后对剩下的符号进行选择
{
case '+':
{
pop(&s1, &n1);
pop(&s1, &n2);
push(&s1, n1 + n2);
break;
}
case '-':
{
pop(&s1, &n1);
pop(&s1, &n2);
push(&s1, n2 - n1);
break;
}
case '*':
{
pop(&s1, &n1);
pop(&s1, &n2);
push(&s1, n1 * n2);
break;
}
case '/':
{
pop(&s1, &n1);
pop(&s1, &n2);
if(n1 != 0)
push(&s1, n2 / n1);
else
{
printf("\n出错:除数不能为零\n");
system("pause");
return -1;
}
break;
}
}
}
pop(&s1, &n1);
printf("\n计算结果为:%d\n\n", n1);
system("pause");
return 0;
}