您的位置:首页 > 编程语言 > C语言/C++

四则运算 C++ 栈实现

2018-01-05 12:34 246 查看
源代码来自http://blog.csdn.net/lub0807/article/details/37884417

注释是自己加上去的,关于中缀表达式转后缀表达式,可以看一下我的这篇文章:

http://blog.csdn.net/include_heqile/article/details/79036631

#include <STDIO.H>
#include <STDLIB.H>

#define MAX_EXP 100         //表达式最大长度
#define MAX_INT 10          //整数最大位数
#define NO_RESULT -99999    //计算异常的返回值

enum node_type{ NUM, OP };

struct node{
int number;
char operation;
enum node_type type;
struct node *next;
};

struct stack{
struct node *top;
int length;
};

typedef struct node Node;
typedef struct stack Stack;

int GetResult(const char []);
void StringToMidExp(const char [], Stack *);
int TenPow(int);
void MidExpToBackExp(Stack *, Stack *);
int BackExpToResult(Stack *);
void ShowStack(const Stack *);
void ShowNode(const Node *);
void InitStack(Stack *);
void Push(Stack *, Node *);
void Pop(Stack *, Node *);
void ClearStack(Stack *);
void Reverse(Stack *, Stack *);

int main(void)
{
char expression[MAX_EXP];
int result;

printf("输入四则运算表达式:\n");
scanf("%s", expression);

result = GetResult(expression);
if (result == NO_RESULT)
{
printf("表达式有误,计算失败。\n");
}
else
{
printf("计算结果是:%d\n", result);
}

return 0;
}

//根据表达式的字符串计算结果
int GetResult(const char exp[])
{
Stack middleExp, backExp;
Stack *pm, *pb;

pm = &middleExp;
pb = &backExp;
InitStack(pm);
InitStack(pb);
StringToMidExp(exp, pm);
printf("中缀表达式:");
ShowStack(pm);
MidExpToBackExp(pm, pb);//后缀表达式存储在pb栈中
printf("后缀表达式:");
ShowStack(pb);

return BackExpToResult(pb);
}

//字符串转换成中缀表达式
//栈ps最后存储的就是原输入的中缀表达式形式
void StringToMidExp(const char exp[], Stack *ps) {
//num数组用来记录数字的字符在相应位置上的值,以便后期还原成数值形式
int num[MAX_INT];
int k, n, count, temp;
Stack m_stack;
Stack *pm;
Node *q;

k = 0;
count = 0;
pm = &m_stack;
InitStack(pm);

while (exp[k] != '\0')//持续循环,直到字符串处理完毕
{
//只要是数字就进行以下处理
if (exp[k] >= '0' && exp[k] <= '9') //数字0到9
{
//48是'0'的ASCII码值
num[count] = exp[k] - 48; //num数组记录整数的每一位
count++;                    //count记录整数的位数
}
//能够进入这条分支的,就是运算符
else if ((exp[k] >= 40 && exp[k] <= 43) || exp[k] == 45 || exp[k] == 47) //运算符
{
//将该运算符之前的字符形式的数字转换成与之对应的数值型
if (count > 0)
{
n = 0;
temp = 0;
//经过该while循环,字符串形式的数字就被转换成了数值型
while (n < count)
{
/**
这里的TenPow是自己定义的一个函数TenPow(n)就是10的n次方
很明显,在nun数组中索引越小的数字位数越高
具体关系就是:
位数 = count-n-1  (n就是num数组中的索引)
*/
temp += num
* TenPow(count - n -1); //每一位乘以10的某次方
n++;
}
//申请一个Node大小的内存空间,并用Node型指针q指向该地址
//给q的数据域和数据类型域赋值
q = (Node *)malloc(sizeof(Node));
q->type = NUM;
q->number = temp;
//将q压进pm栈
Push(pm, q);
}
//为了下一波数字字符串的录入做准备,需要把count重置为0
count = 0; //位数清零
//运算符前面的数字进栈了,接下来就该运算符进栈了
q = (Node *)malloc(sizeof(Node));
//和上面数字进栈的方式相同,先赋值,然后压栈
q->type = OP;
q->operation = exp[k];
Push(pm, q);
}
k++;
}
//既然输入的是一个算数式,那么末尾一定是一个数字
//由于没有运算符了,while循环中的else if语句就不会触发,最后一个数字就不会被转换
//因此需要在循环结束之后处理最后一个数字
if (count > 0) //把最后一个数字转换出来
{
n = 0;
temp = 0;
while (n < count)
{
temp += num
* TenPow(count - n -1);
n++;
}
q = (Node *)malloc(sizeof(Node));
q->type = NUM;
q->number = temp;
Push(pm, q);
}
//颠倒次序之后,在出栈的时候就是按照中缀表达式的从左至右的次序输出的
//从始至终,pm都只是一个局部变量,最后的中缀表达式是保存在ps中的
Reverse(pm, ps); //颠倒一下次序
}

//计算10的n次方
int TenPow(int n)
{
if (n == 0)
{
return 1;
}
else
{
int i, k;
i = 0;
k = 1;
while (i < n)
{
k *= 10;
i++;
}
return k;
}
}

//中缀表达式转换成后缀表达式
//有关中缀表达式转换成后缀表达式的详细内容,可以参考我的这篇博客:
//http://blog.csdn.net/include_heqile/article/details/79036631

void MidExpToBackExp(Stack *pm, Stack *pb)
{
Stack tempStack, oprStack;
Stack *pt, *pr;
Node *q, *r;

pt = &tempStack;    //临时存储后缀表达式
pr = &oprStack;     //用来决定运算符的顺序
InitStack(pt);
InitStack(pr);

//这个while循环就是中缀表达式转换为后缀表达式的处理过程
//每一次循环,都会从中缀表达式的栈中读取出一个元素
while (pm->top)
{
q = (Node *)malloc(sizeof(Node));
Pop(pm, q);
//如果读到的是数字,直接进栈(最终的栈,就是用来存储后缀表达式的栈)
if (q->type == NUM)
{
Push(pt, q);
}
else
{
if (q->operation == '+' || q->operation == '-')
{
//因为对于+和-运算符来说,
//只有 ( 操作符的优先级比他们低
//这时才会停止弹栈,然后他自己再进栈
while (pr->top && pr->top->operation != '(')
{
//弹栈,将弹出的操作符入后缀表达式栈
r = (Node *)malloc(sizeof(Node));
Pop(pr, r);
Push(pt, r);
}
//弹栈停止,自己进后缀表达式栈
Push(pr, q);
}
else if (q->operation == '*' || q->operation == '/')
{
//对于* / 运算符来讲,左括号 ( + - 的优先级都是比他低的
while (pr->top && pr->top->operation != '(' && pr->top->operation != '+' && pr->top->operation != '-')
{
r = (Node *)malloc(sizeof(Node));
Pop(pr, r);
Push(pt, r);
}
Push(pr, q);
}
//左括号是不会进入后缀表达式栈的
else if (q->operation == '(')
{
Push(pr, q);
}
else//这个就是q->operation == ')' 的情况
{
while (pr->top)
{
//一直弹栈,直到碰到左括号
if (pr->top->operation == '(')
{
r = (Node *)malloc(sizeof(Node));
Pop(pr, r);
free(r);
break;
}
r = (Node *)malloc(sizeof(Node));
Pop(pr, r);
Push(pt, r);
}
free(q);
}
}
}
while (pr->top) //栈内剩余运算符全部出栈
{
r = (Node *)malloc(sizeof(Node));
Pop(pr, r);
Push(pt, r);
}
Reverse(pt, pb); //颠倒一下次序
}

//根据后缀表达式计算结果
int BackExpToResult(Stack *ps)
{
if (!ps->top) //空栈说明表达式有误
{
return NO_RESULT;
}

Stack tempStack;
Stack *pt;
Node *q;
int num_left, num_right, result;

pt = &tempStack;
InitStack(pt);
while (ps->top)
{
if (ps->top->type == NUM)
{
q = (Node *)malloc(sizeof(Node));
Pop(ps, q);
Push(pt, q);
}
else
{
q = (Node *)malloc(sizeof(Node));
Pop(pt, q);
num_right = q->number;
free(q);

if (!pt->top) //pt栈内没有第2个数了,说明表达式有误
{
return NO_RESULT;
}

q = (Node *)malloc(sizeof(Node));
Pop(pt, q);
num_left = q->number;
free(q);

q = (Node *)malloc(sizeof(Node));
Pop(ps, q);
switch(q->operation)
{
case '+':
result = num_left + num_right;
break;
case '-':
result = num_left - num_right;
break;
case '*':
result = num_left * num_right;
break;
case '/':
result = num_left / num_right;
break;
}
free(q);

q = (Node *)malloc(sizeof(Node));
q->type = NUM;
q->number = result;
Push(pt, q);
}
}
q = (Node *)malloc(sizeof(Node));
Pop(pt, q);
result = q->number;
free(q);

if (pt->top) //pt栈内还有数字,说明表达式有误
{
return NO_RESULT;
}
else
{
return result;
}
}

//显示栈中元素
void ShowStack(const Stack *ps)
{
if (ps->top)
{
Node *p = ps->top;
while (p->next)
{
ShowNode(p);
printf(" ");
p = p->next;
}
ShowNode(p);
printf("\n");
}
else
{
printf("无\n");
}
}

//显示一个节点元素
void ShowNode(const Node *p)
{
if (p->type == NUM)
{
printf("%d", p->number);
}
else
{
printf("%c", p->operation);
}
}

//初始化栈
void InitStack(Stack *ps)
{
ps->length = 0;
ps->top = NULL;
}

//节点入栈
void Push(Stack *ps, Node *pn)
{
pn->next = ps->top;
ps->top = pn;
ps->length++;
}

//节点出栈
void Pop(Stack *ps, Node *pn)
{
if (ps->top)
{
Node *q = ps->top;
pn->next = NULL;
pn->number = q->number;
pn->operation = q->operation;
pn->type = q->type;
ps->top = q->next;
free(q);
ps->length--;
}
else
{
pn = NULL;
}
}

//清空栈
void ClearStack(Stack *ps)
{
Node *q;

while (ps->top)
{
q = ps->top;
ps->top = q->next;
free(q);
ps->length--;
}
}

//反转栈中元素的次序
void Reverse(Stack *ps1, Stack *ps2)
{
if (ps1->top)
{
Node *q;

ClearStack(ps2);//先把ps2清空,之后将ps1中的元素依次出栈,然后在压到ps2中即可
while (ps1->top)
{
//临时变量,用来暂时存储出栈的元素
q = (Node *)malloc(sizeof(Node));
Pop(ps1, q);
Push(ps2, q);
}
}
else
{
ps2->top = NULL;
ps2->length = 0;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言