遍历表达式过程中,
元素入符号栈的条件:
- 符号栈为空(即此元素是第一个符号);
- 此符号优先级 > 栈顶符号;
- 前一个符号为 '(' 且此符号不是 ')' ;
先进行阶段性计算的条件:
- 表达式已经全部遍历结束(无论有没有计算结束);
- 遍历到符号时,此符号的优先级 <= 栈顶元素;
- 遍历到符号时,此符号为 ')' 且前一个符号不是 ')' ;
表达式中有 '()' 存在时,要设置其优先级为最高。而且其中的运算结束后要手动将 '(' 出栈。
linkstack.h
#ifndef __LINKSTACK_H__
#define __LINKSTACK_H__
typedef struct stack_s
{
int data;
struct stack_s *next;
}stack_t;
#define SUCCESS 0
#define FAILED -1
#define TRUE 1
#define FALSE -2
void stack_display(stack_t *top);
int stack_init(stack_t **top);
int push(stack_t **top,int data);
int pop(stack_t **top);
int stack_isempty(stack_t *top);
int get_top(stack_t *top);
#endif
linkstack.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linkstack.h"
void stack_display(stack_t *top)
{
stack_t *tmp = top->next;
if(top == NULL||top->next == NULL)
{
return ;
}
printf("========top========\n");
while(tmp)
{
printf("%d\n",tmp->data);
tmp = tmp->next;
}
printf("=======bottom=======\n");
}
int stack_init(stack_t **top)
{
*top = (stack_t *)malloc(sizeof(stack_t));
if(*top == NULL)
{
printf("stack_init failed\n");
return FAILED;
}
memset(*top,0,sizeof(stack_t));
(*top)->next = NULL;
(*top)->data = -1;
return SUCCESS;
}
int push(stack_t **top,int data)
{
stack_t *new_node = NULL;
if(*top == NULL)
{
printf("top is NULL\n");
return FAILED;
}
new_node = (stack_t *)malloc(sizeof(stack_t));
if(new_node == NULL)
{
printf("push malloc failed\n");
return FAILED;
}
memset(new_node,0,sizeof(stack_t));
new_node->data = data;
new_node->next = (*top)->next;
(*top)->next = new_node;
return SUCCESS;
}
int pop(stack_t **top)
{
int data;
stack_t *tmp = (*top)->next;
if(*top == NULL || (*top)->next == NULL)
{
printf("stack is NULL\n");
return FAILED;
}
data = tmp->data;
(*top)->next = tmp->next;
tmp->next = NULL;
free(tmp);
return data;
}
int stack_isempty(stack_t *top)
{
if(top == NULL || top->next == NULL)
return TRUE;
else
return FALSE;
}
int get_top(stack_t *top)
{
if(top == NULL || top->next == NULL)
{
printf("stack is NULL\n");
return FAILED;
}
return top->next->data;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linkstack.h"
int priority(char opt)
{
switch(opt)
{
case '(':
return 3;
case '*':
case '/':
return 2;
case '+':
case '-':
return 1;
default :
return 0;
}
}
int main()
{
stack_t *s_num = NULL;
stack_t *s_opt = NULL;
char expr[1024] = {0};
int tmp = 0;
int num1 = 0;
int num2 = 0;
int i = 0;
int ret;
//判空
if(stack_init(&s_num) == FAILED || stack_init(&s_opt) == FAILED)
{
printf("stack_init failed\n");
return FAILED;
}
printf("please input expr:");
scanf("%s",expr);
/* ?????? */
while(expr[i] != '\0' || stack_isempty(s_opt) != TRUE)
{ //如果数字和符号已经全部入栈 或者数字和符号已经全部入栈但是运算还没有完全结束,就继续循环
while(expr[i] >= '0' && expr[i] <= '9')
{ //只要是数字,就进来转化 并且 i 后移
tmp = tmp * 10 + expr[i] - '0';
i++;
if(expr[i] < '0' || expr[i] > '9')
{ //只要下一个字符是符号,就将先前转化好的数字入栈 出了这个while之后,符号另作处理
ret = push(&s_num, tmp);
if(ret == FAILED)
{
printf("push failed\n");
return FAILED;
}
tmp = 0; //tmp用完之后要置 0 ,以备下次重新赋值使用
}
}
//清除符号栈残余的'(' //有 '()' 的情况下, '()' 里的运算结束之后‘(’仍在符号栈内,需要手动清除
if(expr[i] == ')' && get_top(s_opt) == '(')
{ //如果此符号是 ')' 并且经过计算后栈顶符号是 '(' ,就将 '(' pop出去
pop(&s_opt);
i++;
continue; //符号入栈后立即结束当前次循环,进行新一轮的while判断
}
if((stack_isempty(s_opt) == TRUE) ||
//如果符号栈为空 或者
(priority(expr[i]) > priority(get_top(s_opt)))||
//此符号的优先级 > 栈顶符号 或者
((get_top(s_opt) == '(') && (expr[i] != ')')))
//栈顶符号为 '(' 并且此符号不是 ')'
{ /*就将符号入栈 并且 i 后移*/
push(&s_opt, expr[i]);
i++;
continue; //表达式中符号后面必定为数字,所以必须要重启大循环
}
/* 不需要 */
if(((expr[i] == '\0' )&&(stack_isempty(s_opt) != TRUE))||
//如果表达式入栈完毕并且符号栈有符号, 或者
(priority(expr[i]) <= priority(get_top(s_opt)))||
//此符号的优先级 < = 栈顶符号, 或者
((expr[i] == ')' && get_top(s_opt) != '(')))
//此符号是 ')' 并且栈顶符号不是 '(' (表达式入栈时候会出现的情况) ,
{ /* 就先计算 */
switch (pop(&s_opt))
{
case '+':
num2 = pop(&s_num);
num1 = pop(&s_num);
push(&s_num,(num1 + num2));//阶段性的计算结果先入栈而不是马上输出是为了后续计算使用
break;
case '-':
num2 = pop(&s_num);
num1 = pop(&s_num);
push(&s_num,(num1 - num2));
break;
case '*':
num2 = pop(&s_num);
num1 = pop(&s_num);
push(&s_num,(num1 * num2));
break;
case '/':
num2 = pop(&s_num);
num1 = pop(&s_num);
push(&s_num,(num1 / num2));
break;
default :
return FAILED;
}
}
}
printf("reslut is %d\n",get_top(s_num));
return 0;
}
#if 0
int main()
{
int ret;
int i;
stack_t *top = NULL;
ret = stack_init(&top);
if(ret == FAILED)
{
printf("stack_init failed\n");
return FAILED;
}
for(i = 0;i < 5;i++)
{
ret = push(&top, i);
if(ret == FAILED)
{
printf("push failed\n");
return FAILED;
}
}
if(stack_isempty(top) == TRUE)
printf("satck is NULL\n");
else
printf("stack is not NULL\n");
ret = get_top(top);
if(ret == FAILED)
{
printf("get_top failed\n");
return FAILED;
}
printf("top data is %d\n",ret);
stack_display(top);
for(i = 0; i< 5;i++)
{
ret = pop(&top);
if(ret == FAILED)
{
printf("pop failed\n");
return FAILED;
}
printf("pop data is %d\n",ret);
}
if(stack_isempty(top) == TRUE)
printf("satck is NULL\n");
else
printf("stack is not NULL\n");
stack_display(top);
return 0;
}
#endif