zoukankan      html  css  js  c++  java
  • 数据-第16课-栈的应用实战二

    第16课-栈的应用实战二

    1. 问题的提出

    计算机的本质工作就是数学运算,那计算机可以读入字符串”9 + (3 - 1) *5 +8/2”并且计算值吗?

    2. 后缀表达式

    波兰科学家在20世纪50年代提出了一种将运算符放在数字后面的后缀表达式。

    对应的,我们平时用的数学表达式叫做中缀表达式。

    实例

    5 + 3 => 5 3 +

    1 + 2 * 3 => 1 2 3 * +

    9 + ( 3–1 ) * 5 => 9 3 1–5 * +

    中缀表达式符合人类的阅读和思维习惯;后缀表达式符合计算机的“运算习惯”。

    3. 解决方案

    遍历中缀表达式中的数字和符号。

    对于数字:直接输出 。

    对于符号:

    左括号:进栈

    符号:与栈顶符号进行优先级比较,栈顶符号优先级低:进栈

    栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈 ,之后进栈

    右括号:将栈顶符号弹出并输出,直到匹配左括号

    遍历结束:将栈中的所有符号弹出并输出。

    4. 整体框架

    transform(exp)

    {

             创建栈 s;

             i = 0;

            

             while(exp[i] != '')

             {

                      if(exp[i]为数字)

                      {

                               Output(exp[i]);         

                      }

                      else if(exp[i]为符号)

                      {

                               while(exp[i]优先级 <= 栈顶符号优先级)

                               {

                                        output(栈顶优先级);

                                        Pop(S);     

                               }

                               Push(S,exp[i]); 

                      }

                      else if(exp[i]为右括号)

                      {

                               while(栈顶符号不为括号)

                               {

                                        output(栈顶符号);

                                        Pop(S);     

                               }       

                      }

                      从S中弹出左括号;

                      else

                      {

                               报错,停止循环;        

                      }

                      i++;        

             }

             while((Size(S) > 0)&&(exp[i]==''))

             {

                      output(栈顶符号);

                      Pop(S);     

             }

    }

    5. 中缀转后缀的算法

    #include <stdio.h>

    #include "LinkStack.h"

    int isNumber(char c)

    {

        return ('0' <= c) && (c <= '9');

    }

    int isOperator(char c)

    {

        return (c == '+') || (c == '-') || (c == '*') || (c == '/');

    }

    int isLeft(char c)

    {

        return (c == '(');

    }

    int isRight(char c)

    {

        return (c == ')');

    }

    int priority(char c)

    {

        int ret = 0;

       

        if( (c == '+') || (c == '-') )

        {

            ret = 1;

        }

       

        if( (c == '*') || (c == '/') )

        {

            ret = 2;

        }

       

        return ret;

    }

    void output(char c)

    {

        if( c != '' )

        {

            printf("%c", c);

        }

    }

    void transform(const char* exp)

    {

        LinkStack* stack = LinkStack_Create();

        int i = 0;

       

        while( exp[i] != '' )

        {

            if( isNumber(exp[i]) )

            {

                output(exp[i]);

            }

            else if( isOperator(exp[i]) )

            {

                while( priority(exp[i]) <= priority((char)(int)LinkStack_Top(stack)) )

                {

                    output((char)(int)LinkStack_Pop(stack));

                }

               

                LinkStack_Push(stack, (void*)(int)exp[i]);

            }

            else if( isLeft(exp[i]) )

            {

                LinkStack_Push(stack, (void*)(int)exp[i]);

            }

            else if( isRight(exp[i]) )

            {

                char c = '';

               

                while( !isLeft((char)(int)LinkStack_Top(stack)) )

                {

                    output((char)(int)LinkStack_Pop(stack));

                }

               

                LinkStack_Pop(stack);

            }

            else

            {

                printf("Invalid expression!");

                break;

            }

           

            i++;

        }

       

        while( (LinkStack_Size(stack) > 0) && (exp[i] == '') )

        {

            output((char)(int)LinkStack_Pop(stack));

        }

       

        LinkStack_Destroy(stack);

    }

    int main()

    {

        transform("9+(3-1)*5+8/2");

       

        printf(" ");

       

        return 0;

    }

    6. 计算机的计算习惯

    计算机对后缀表达式的运算是基于栈的

    解决方案:

    遍历后缀表达式中的数字和符号

    对于数字:进栈

    对于符号:

    从栈中弹出右操作数

    从栈中弹出左操作数

    根据符号进行运算

    将运算结果压入栈中

    便利结束:栈中的唯一数字为计算结果

    7. 算法框架

    compute(exp)

    {

             创建栈 S;

             i = 0;

            

             while(exp[i] != '')

             {

                      if(exp[i] 为数字)

                      {

                               Push(S,exp[i]); 

                      }       

                      else if(exp[i]为符号)

                      {

                               1、丛栈中弹出右操作数;

                               2、从栈中弹出左操作数;

                               3、根据符号进行运算;

                               4、Push(stack,结果);     

                      }

                      else

                      {

                               报错,停止循环;        

                      }

                      i++;

             }

             if((Size(S) == 1) && (exp[i] == ''))

             {

                      栈中唯一的数字为运算结果;    

             }

             返回结果;           

    }

    程序:

    #include <stdio.h>

    #include "LinkStack.h"

    int isNumber(char c)

    {

        return ('0' <= c) && (c <= '9');

    }

    int isOperator(char c)

    {

        return (c == '+') || (c == '-') || (c == '*') || (c == '/');

    }

    int value(char c)

    {

        return (c - '0');

    }

    int express(int left, int right, char op)

    {

        int ret = 0;

       

        switch(op)

        {

            case '+':

                ret = left + right;

                break;

            case '-':

                ret = left - right;

                break;

            case '*':

                ret = left * right;

                break;

            case '/':

                ret = left / right;

                break;

            default:

                break;

        }

       

        return ret;

    }

    int compute(const char* exp)

    {

        LinkStack* stack = LinkStack_Create();

        int ret = 0;

        int i = 0;

       

        while( exp[i] != '' )

        {

            if( isNumber(exp[i]) )

            {

                LinkStack_Push(stack, (void*)value(exp[i]));

            }

            else if( isOperator(exp[i]) )

            {

                int right = (int)LinkStack_Pop(stack);

                int left = (int)LinkStack_Pop(stack);

                int result = express(left, right, exp[i]);

               

                LinkStack_Push(stack, (void*)result);

            }

            else

            {

                printf("Invalid expression!");

                break;

            }

           

            i++;

        }

       

        if( (LinkStack_Size(stack) == 1) && (exp[i] == '') )

        {

            ret = (int)LinkStack_Pop(stack);

        }

        else

        {

            printf("Invalid expression!");

        }

       

        LinkStack_Destroy(stack);

       

        return ret;

    }

    int main()

    {

        printf("9 + (3 - 1) * 5 + 8 / 2 = %d ", compute("931-5*+82/+"));

       

        return 0;

    }

    小结:

    中缀表达式是人习惯的表达方式。

    后缀表达式是计算机喜欢的表达方式。

    通过栈可以方便的将中缀形式变换为后缀形式。

    中缀表达式的计算过程类似程序编译运行的过程。

  • 相关阅读:
    PHP之常用设计模式
    MySQL之慢查询日志和通用查询
    mysql之找回误删数据
    PHPer未来路在何方...
    如何成为更优秀的程序员
    常见的 CSRF、XSS、sql注入、DDOS流量攻击
    API接口TOKEN设计
    成为更好的程序员的八中途径
    奉秉格言
    PHP优化与提升
  • 原文地址:https://www.cnblogs.com/free-1122/p/11322780.html
Copyright © 2011-2022 走看看