第13节 栈的应用实战二

Source
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pt_raspi_fresher/article/details/87212574

-------------------------------------资源来源于网络,仅供自学使用,如有侵权,联系我必删.

第一:

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

    中缀表达式                 后缀表达式

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

 

第二:

将中缀表达式转换成后缀表达式 的计算方法:

?  遍历中缀表达式中的数字和符号
?  对于数字 : 直接输出
?  对于符号 :
    •  左括号 : 进栈
    •  符号 : 与栈顶符号进行优先级比较
                 •  栈顶符号优先级低 : 进栈
                 •  栈顶符号优先级不低 : 将栈顶符号弹出并输出 , 之后进栈
    •  右括号 : 将栈顶符号弹出并输出 , 直到匹配左括号
?  遍历结束 : 将栈中的所有符号弹出并输出

 

第三:

算法框架

 

第四:

中缀表达式变后缀表达式

基于LinkList.cLinkList.h 链表和LinkStack.cLinkStack.h 链式栈 实现

#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 != '\0' )
    {
        printf("%c", c);
    }
}

void transform(const char* exp)
{
    LinkStack* stack = LinkStack_Create();
    int i = 0;
    
    while( exp[i] != '\0' )
    {
        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 = '\0';
            
            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] == '\0') )
    {
        output((char)(int)LinkStack_Pop(stack));
    }
    
    LinkStack_Destroy(stack);
}

int main()
{
    transform("9+(3-1)*5+8/2");
    
    printf("\n");
    
    return 0;
}

第五:

计算机对后缀表达式的运算

1.解决方案

?  遍历后缀表达式中的数字和符号
?  对于数字 : 进栈
?  对于符号 :
    •  从栈中弹出右操作数
    •  从栈中弹出左操作数
    •  根据符号进行运算
    •  将运算结果压入栈中
?  遍历结束 :栈中的唯一数字为计算结果

 

2.算法框架

 

3.后缀表达式的计算

#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] != '\0' )
    {
        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] == '\0') )
    {
        ret = (int)LinkStack_Pop(stack);
    } 
    else 
    {
        printf("Invalid expression!");
    }
    
    LinkStack_Destroy(stack);
    
    return ret;
}

int main()
{
    printf("9 + (3 - 1) * 5 + 8 / 2 = %d\n", compute("931-5*+82/+"));
    
    return 0;
}

小结

?  中缀表达式是人习惯的表达方式
?  后缀表达式是计算机喜欢的表达方式
?  通过栈可以方便的将中缀形式变换为后缀形式
? 中缀表达式的计算过程类似程序编译运行的过程