zoukankan      html  css  js  c++  java
  • c语言表达式求值 中缀表达式转后缀表达式 求值

    中转后 具体转换方式:

    1.从左到右遍历需要计算的字符串

    2.若是运算数,直接压入后缀表达式栈

    3.若是左括号,直接压入运算符栈,(括号是最高优先级,无需比较)(入栈后优先级降到最低,确保其他符号正常入栈)

    4.若是右括号,(意味着括号已结束)不断弹出运算符栈顶运算符并输出到后缀表达式栈

    直到遇到左括号(弹出但不输出)

    5.运算符,将该运算符与运算符栈顶运算符进行比较,

    如果优先级高于栈顶运算符则压入运算符栈(该部分运算还不能进行),

     如果优先级低于等于栈顶运算符则将栈顶运算符弹出到后缀表达式栈然后比较新的栈顶运算符.

    (低于弹出意味着前面部分可以运算,先输出到后缀表达式栈一定是高优先级运算符,

    等于弹出是因为同等优先级,从左到右运算)

    直到优先级大于栈顶运算符或者栈空,再将该运算符入运算符栈

    6.如果字符串处理完毕,则按顺序从运算符栈弹出所有运算符到后缀表达式栈

    使用后缀表达式计算的方法:

    1、 按顺序取后缀表达式的每个值

    2、 若是数字 则入栈

    3、 若是操作符 则从栈取出两个数字 进行运算 运算之后再将结果入栈

    4、 循环上述过程知道后缀表达式结束 栈顶元素(栈中只有一个元素)即为结果

      1 #include <windows.h>
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <malloc.h>
      5 #define NUM 0
      6 #define OPERATION 1
      7 typedef struct {//栈中的结点
      8     int val;
      9     int type;
     10 } Node;
     11 typedef struct {//
     12     const char* name;//栈名
     13     Node* sta;//结点
     14     int size;//最多存储多少个元素
     15     int cnt;//当前存储了多少个元素
     16 } MyStack;
     17 void trace(MyStack* s)//栈的遍历
     18 {
     19     int i;
     20     printf("%s栈中的元素为:", s->name);
     21     for (i = 0; i < s->cnt; i++) {
     22         if (s->sta[i].type == NUM) {//若是数字
     23             printf("%d ", s->sta[i].val);
     24         }
     25         else {//若是字符
     26             printf("%c ", (char)s->sta[i].val);
     27         }
     28     }
     29     printf("
    ");
     30 }
     31 void sFree(MyStack* s)//释放栈
     32 {
     33     if (s->sta != NULL) {
     34         free(s->sta);
     35         s->sta = NULL;
     36     }
     37     return;
     38 }
     39 int sInit(MyStack* s, const char* name, int size)//初始化栈
     40 {
     41     s->name = name;
     42     s->size = size;
     43     s->sta = (Node*)calloc(s->size, sizeof(Node));//calloc申请后 其中存的都是0
     44     if (s->sta == NULL) {
     45         return -1;//分配失败
     46     }
     47     s->cnt = 0;//当前栈中元素有0个
     48     return 0;//分配成功
     49 }
     50 void sPush(MyStack* s, Node item)//入栈一个元素
     51 {
     52     if (s->cnt == s->size) {
     53         printf("栈空间不足
    ");
     54         return;
     55     }
     56     s->sta[s->cnt] = item;
     57     s->cnt++;
     58     return;
     59 }
     60 bool sIsEmpty(MyStack* s)//判断栈是否为空
     61 {
     62     return s->cnt == 0;
     63 }
     64 void sPop(MyStack* s, Node* item)//删除栈顶元素 并返回值到item
     65 {
     66     if (sIsEmpty(s)) {
     67         return;
     68     }
     69     *item = s->sta[s->cnt - 1];
     70     s->cnt--;
     71     return;
     72 }
     73 void sTop(MyStack* s, Node* item)//获得栈顶元素到item  不删除栈顶袁术
     74 {
     75     if (sIsEmpty(s)) {
     76         return;
     77     }
     78     *item = s->sta[s->cnt - 1];
     79     return;
     80 }
     81 bool myIsNum(char ch)//判断是否是数字
     82 {
     83     return ch >= '0' && ch <= '9';
     84 }
     85 bool myIsOper(char ch)//判断是否是运算符
     86 {
     87     return ch == '+' || ch == '-' || ch == '*' || ch == '/'||ch=='('||ch==')';
     88 }
     89 //处理数值
     90 void procNum(MyStack* postfix_expression, char* s, int len, int* pi)
     91 {
     92     int i = *pi;//令i等于当前在处理的元素的坐标
     93     int num=0;//当前数字的值 具体是多少
     94     Node item_num;
     95     while (myIsNum(s[i]))
     96     {
     97         num = num * 10 + s[i]-'0';
     98         i++;
     99     }
    100     //新建结点
    101     item_num.type = NUM;
    102     item_num.val = num;
    103     //数字直接入后缀表达式的栈
    104     sPush(postfix_expression, item_num);
    105     *pi = i-1;//改变calculate_postfix_expression 中i的值
    106     return;
    107 }
    108 //处理运算符
    109 void procOper(MyStack* postfix_expression, MyStack* s_oper, char* s, int len, int* pi)
    110 {
    111     int i = *pi;
    112     Node item;
    113     Node top_item;
    114     Node pop_item;
    115     if (s[i] == '(')//如果是( 直接存入运算符栈
    116     {
    117         item.type = OPERATION;
    118         item.val = s[i];
    119         sPush(s_oper, item);
    120     }
    121     else if (s[i] == ')')//若是) 则弹出到(为止
    122     {
    123         int flag = 0;//是否找到了 (
    124         while (!sIsEmpty(s_oper)) {
    125             sPop(s_oper, &pop_item);
    126             if (pop_item.val == '(') {//若找到了左括号退出
    127                 flag = 1;
    128                 break;
    129             }
    130             sPush(postfix_expression, pop_item);//若未找到左括号 则一直从运算符栈中pop
    131         }
    132         if (!flag)
    133         {
    134             printf("括号不匹配!");
    135             exit(0);
    136         }
    137     }
    138     //如果是乘除
    139     else if (s[i] == '*' || s[i] == '/') 
    140     {
    141         item.type = OPERATION;
    142         item.val = s[i];
    143         while (!sIsEmpty(s_oper)) {
    144             sTop(s_oper, &top_item);
    145             //如果当前运算符栈的栈顶是+ - (
    146             //则* /级别较高 则跳出循环
    147             if (top_item.val == '+' || top_item.val == '-' || top_item.val == '(') {
    148                 break;
    149             }
    150             //若当前运算符栈顶不是+ - ( 则是* /
    151             //则需先把* / pop完 
    152             sPop(s_oper, &pop_item);
    153             sPush(postfix_expression, pop_item);
    154         }
    155         //才能将当* /入栈
    156         sPush(s_oper, item);
    157     }
    158     //如果是 + -
    159     else if (s[i] == '+' || s[i] == '-')
    160     {
    161         item.type = OPERATION;
    162         item.val = s[i];
    163         while (!sIsEmpty(s_oper)) {
    164             sTop(s_oper, &top_item);
    165             //如果当前运算符栈的栈顶是 (
    166             //则当前运算符级别较高 则跳出循环
    167             if (top_item.val == '(') {
    168                 break;
    169             }
    170             //若当前运算符栈顶不是 ( 则是+ - * /
    171             //则需先把+ - * /pop完 
    172             sPop(s_oper, &pop_item);
    173             sPush(postfix_expression, pop_item);
    174         }
    175         //才能将当+ - 入栈
    176         sPush(s_oper, item);
    177     }
    178     else 
    179     {
    180         printf("输入了非空格 非数字 非运算符的元素 %c
    ", s[i]);
    181         exit(0);
    182     }
    183     return;
    184 }
    185 //计算后缀表达式 存储在s_trans中
    186 void calculate_postfix_expression(MyStack* postfix_expression, MyStack* s_oper, char* s, int len)
    187 {
    188     int i;
    189     int ret;
    190     int num;
    191     Node item;
    192     for (i = 0; i < len; i++) {
    193         if (s[i] == ' ') {//当前输入为空格时 跳过
    194             continue;
    195         }
    196         if (myIsNum(s[i])) {//当前是数字时
    197             procNum(postfix_expression, s, len, &i);
    198             continue;
    199         }
    200         if (myIsOper(s[i])) {//当前是运算符时 进入运算的处理程序
    201             procOper(postfix_expression, s_oper, s, len, &i);
    202             continue;
    203         }
    204         printf("输入了非空格 非数字 非运算符的元素 %c
    ", s[i]);
    205         exit(0);
    206     }
    207     //若运算栈不为空 依次pop出运算栈中的元素 再push到后缀表达式栈
    208     while (!sIsEmpty(s_oper)) {
    209         sPop(s_oper, &item);
    210         sPush(postfix_expression, item);
    211     }
    212     return;
    213 }
    214 int cal(MyStack* postfix_expression, MyStack* s_num)//进行计算
    215 {
    216     int i;
    217     Node n1, n2;
    218     Node item;
    219     //顺序取出栈中的每个元素
    220     for (i = 0; i < postfix_expression->cnt; i++) {
    221         //item为后缀表达式中顺序取的第i个元素
    222         item = postfix_expression->sta[i];
    223         //若一直是数字 则一直放进数字栈
    224         if (item.type == NUM) {
    225             sPush(s_num, item);
    226             continue;//开始下一次循环
    227         }
    228         //执行到这里证明不是数字 是运算符了
    229         sPop(s_num, &n2);//从栈中拿出两个元素到n2 n1中
    230         sPop(s_num, &n1);
    231         if (item.val == '+') {
    232             n1.val += n2.val;
    233         }
    234         else if (item.val == '-') {
    235             n1.val -= n2.val;
    236         }
    237         else if (item.val == '*') {
    238             n1.val *= n2.val;
    239         }
    240         else {
    241             n1.val /= n2.val;
    242         }
    243         sPush(s_num, n1);//再将此次运算结果入数字栈
    244     }
    245     return s_num->sta[0].val;//最后数字栈中的第一个元素就是 计算结果
    246 }
    247 int calculate(char* s) {//进行计算
    248     int ret;
    249     int len;
    250     if (s == NULL||(len=strlen(s))==0) {
    251         return 0;
    252     }
    253     MyStack s_num;//数字栈
    254     MyStack s_oper;//运算符栈
    255     MyStack postfix_expression;//后缀表达式栈
    256     if (sInit(&s_num, "数字", len)==-1||
    257         sInit(&s_oper, "运算符", len)==-1||
    258         sInit(&postfix_expression, "后缀表达式", len)==-1
    259         ) //若初始化三个栈失败的话 则释放内存 return 0
    260     {
    261         sFree(&s_num);
    262         sFree(&postfix_expression);
    263         sFree(&s_oper);
    264         return 0;
    265     }
    266     //计算后缀表达式
    267     calculate_postfix_expression(&postfix_expression, &s_oper, s, len);
    268     //显示后缀表达式
    269     trace(&postfix_expression);
    270     //使用后缀表达是进行计算
    271     ret = cal(&postfix_expression, &s_num);
    272     //释放栈的空间
    273     sFree(&postfix_expression);
    274     sFree(&s_oper);
    275     sFree(&s_num);
    276     //返回结果
    277     return ret;
    278 }
    279 int main()
    280 {
    281     char str[10000];
    282     scanf("%[^
    ]", str);//可以输入空格 回车停止输入
    283     printf("计算结果为%d
    ", calculate(str));
    284 }
    285 //例子 (((50+20)+(2*3))/14)
  • 相关阅读:
    (原创)在ER/Studio中使用宏把Attribute name复制到Definition
    Xming + PuTTY 在Windows下远程Linux主机使用图形界面的程序
    一个时间日期转换格式的小功能(Oracle)
    C#正则表达式整理备忘【转】
    【转】一篇好文,以在迷茫时阅读
    经常关注的、极具参考价值的网站收集(无限畅想版)
    中文分词备忘
    我心目中的编程高手
    网站推荐
    通过手机短信控制电脑
  • 原文地址:https://www.cnblogs.com/lancelee98/p/13260299.html
Copyright © 2011-2022 走看看