数据结构 栈的应用 --表达式求值

一: 中缀表达式求值 

思想:

需要2个栈,运算对象栈OPND,运算符栈OPTR,

1:将栈OPND初始化为空,栈OPTR初始化为表达式的定界符#

2:扫描表达式,直到遇到结束符#

  2.1:当前字符是运算对象,入栈OPND

  2.2:当前字符是运算符且优先级比栈OPTR的栈顶运算符优先级高,入栈OPTR,处理下一个字符

  2.3:当前字符是运算符且优先级比栈OPTR的栈顶运算符优先级低,则从栈OPND出栈2个运算对象,从栈OPTR出栈一个运算符进行运算,并将运算结果入栈OPND,处理当前字符

  2.4:当期字符是运算符且优先级与栈OPTR的栈顶运算符的优先级相同,将栈OPTR的栈顶运算符出栈,出理下一个字符。

3:输出栈OPND中的栈顶元素,即运算结果

//expseqstack.h
//10只是示例性的数据,可以根据实际问题具体定义
const int StackSize=10;
typedef struct
{
	char op;
	int inputprecedence;
	int stackprecedence;
}DataType1;

template <class T>       //定义模板类SeqStack
class SeqStack
{
public:
    SeqStack();            //构造函数,栈的初始化
	~SeqStack();            //析构函数
	void init();
    void Push(T x);          //将元素x入栈
    T Pop();                //将栈顶元素弹出
    T GetTop();	         //取栈顶元素(并不删除)
	bool Empty();           //判断栈是否为空
public:
    T data[StackSize];      //存放栈元素的数组
    int top;                //栈顶指针,指示栈顶元素在数组中的下标
};

/*
 * 前置条件:栈不存在
 * 输    入:无
 * 功    能:栈的初始化
 * 输    出:无
 * 后置条件:构造一个空栈
 */

template <class T>
SeqStack<T>::SeqStack()
{
	top=-1;
}

/*
 * 前置条件:栈已存在
 * 输    入:无
 * 功    能:销毁栈
 * 输    出:无
 * 后置条件:释放栈所占用的存储空间
 */

template <class T>
SeqStack<T>::~SeqStack()
{

} 

template <class T>
void SeqStack<T>::init()
{
	top=0;
} 

/*
 * 前置条件:栈已存在
 * 输    入:元素值x
 * 功    能:在栈顶插入一个元素x
 * 输    出:如果插入不成功,抛出异常
 * 后置条件:如果插入成功,栈顶增加了一个元素
 */

template <class T>
void SeqStack<T>::Push(T x)
{
    if (top== StackSize-1) throw "上溢";
    top++;
    data[top]=x;
}

/*
 * 前置条件:栈已存在
 * 输    入:无
 * 功    能:删除栈顶元素
 * 输    出:如果删除成功,返回被删元素值,否则,抛出异常
 * 后置条件:如果删除成功,栈顶减少了一个元素
 */     

template <class T>
T SeqStack<T>::Pop()
{
    T x;
    if (top==-1) throw "下溢";
    x=data[top--];
    return x;
}

/*
 * 前置条件:栈已存在
 * 输    入:无
 * 功    能:读取当前的栈顶元素
 * 输    出:若栈不空,返回当前的栈顶元素值
 * 后置条件:栈不变
 */

template <class T>
T SeqStack<T>::GetTop()
{
	if (top!=-1)
    return data[top];
}

/*
 * 前置条件:栈已存在
 * 输    入:无
 * 功    能:判断栈是否为空
 * 输    出:如果栈为空,返回1,否则,返回0
 * 后置条件:栈不变
 */

template <class T>
bool SeqStack<T>::Empty()
{
	if(top==-1) return 1;
	else return 0;
}

  

//main.cpp
#include"expseqstack.h"
#include<iostream>
#include<string>
using namespace std;

//检查符号之间的优先级,1表示>,0表示=,-1表示<,c1栈内的运算,c2栈外的运算
int check(char c1, char c2)
{
    int a1, a2;
    if (c1 == ‘+‘ || c1 == ‘-‘)
        a1 = 3;
    if (c1 == ‘*‘ || c1 == ‘/‘)
        a1 = 5;
    if (c1 == ‘(‘)
        a1 = 1;
    if (c1 == ‘)‘)
        a1 = 7;
    if (c1 == ‘#‘)
        a1 = 0;  

    if (c2 == ‘+‘ || c2 == ‘-‘)
        a2 = 2;
    if (c2 == ‘*‘ || c2 == ‘/‘)
        a2 = 4;
    if (c2 == ‘(‘)
        a2 = 6;
    if (c2 == ‘)‘)
       a2 = 1;
    if (c2 == ‘#‘)
        a2 = 0;  

    if (a1 > a2)
        return 1;
    if (a1 == a2)
        return 0;
    if (a1 < a2)
        return -1;
}  

//符号运算函数
double sum(char c, double d1, double d2)
{
    switch (c)
    {
    case ‘+‘:
        return d1 + d2;
        break;
    case ‘-‘:
        return d1 - d2;
        break;
    case ‘*‘:
        return d1 * d2;
        break;
    case ‘/‘:
        return d1 / d2;
       break;
    default:
        break;
    }
}  

int main()
{
   char *op = "+-*/()#";
    string str;
    cout<<"请输入表达式:"<<endl;
	cin>>str;  

   //给表达式字符串str添加‘#’结束标志符
    str.append(1, ‘#‘);
    SeqStack<char> OPTR;//运算符栈
   SeqStack<double> OPND;//操作数栈
    int a = -1;
    //先将‘#‘入栈
   OPTR.Push(‘#‘);
    while (true)
   {
        int b = a + 1;
        a = str.find_first_of(op, a + 1);
        if (a == string::npos)
           break;
        if (a != b)
       {
            string ss(str, b, a - b);
            double d = atof(ss.c_str());
            //数据先入栈
            OPND.Push(d);
        }
        //运算符优先级比较
        char val;
        val=OPTR.GetTop();
        int che = check(val, str[a]);
          if (-1 == che)//栈外优先级大直接入栈
          {
              OPTR.Push(str[a]);
          }
          if (0 == che)//栈内外优先级相等则出栈
          {
              OPTR.Pop();
          }
          if (1 == che)//栈内优先级大,出栈进行运算
          {
              char val;  double d1;    double d2;
              val=OPTR.GetTop();  

              d1=OPND.GetTop();
              d1=OPND.Pop();  

              d2=OPND.GetTop();
              d2=OPND.Pop();
              d1 = sum(val, d2, d1);
              //运算结果入栈
              OPND.Push(d1);
              OPTR.Pop();
              a--;
          }
    }
    double s;
    s=OPND.GetTop();
    cout <<s<<endl;
    return 0;
}

  二:中缀表达式转后缀表达式并求值

中缀表达式转后缀表达式思想:

1:栈S初始化为空栈

2:扫描表达式的每个字符,

  2.1:当前字符是运算对象,输出此字符,处理下一个字符

  2.2:当前字符是运算符且优先级比栈S的栈顶的运算符优先级高,此字符入栈S,处理下一个字符

  2.3:当前字符是运算符且优先级比栈S的栈顶的运算符优先级低,则将栈S的栈顶元素弹出并输出

  2.4:当前字符是运算符且优先级比栈S的栈顶的运算符优先级相同,则将栈S的栈顶元素弹出,处理下一个字符

注:只有遇到 ) 的情况下,才弹出  (  ,但不输出。

例子:中缀表达式 3*(4+2)/2-5     ====>>后缀表达式3 4 2 + * 2 / 5 -

3  后缀表达式求值:

  1:初始化栈S

  2:扫描当前表达式

    2.1当前字符是运算对象,则入栈S,处理下一个字符

    2.2当前字符是运算符,则从栈S出栈2个运算对象,执行运算并将结果入栈S,处理下一个字符

  3:输出栈S的栈顶元素,就是表达式结果。

//头文件 PrefixToPostfix.h
#include <vector>
using namespace std;  

bool isoperator(char op);                         // 判断是否为运算符
int priority(char op);                            // 求运算符优先级
void postfix(char pre[] , char post[],int &n);    // 把中缀表达式转换为后缀表达式
double read_number(char str[],int *i);            // 将数字字符串转变成相应的数字
double postfix_value(char post[]);                // 由后缀表达式字符串计算相应的中值表达式的值   
//PrefixToPostfix.cpp

#include "PrefixToPostfix.h"
#include"expseqstack.h"
#include <iostream>
using namespace std;  

bool isoperator(char op)
{
   switch(op)
    {
    case ‘+‘:
    case ‘-‘:
    case ‘*‘:
    case ‘/‘:
        return 1;
    default :
        return 0;
   }
}  

int priority(char op)
{
   switch(op)
    {
    case ‘#‘:
        return -1;
    case ‘(‘:
        return 0;
    case ‘+‘:
    case ‘-‘:
        return 1;
    case ‘*‘:
    case ‘/‘:
        return 2;
    default :
       return -1;
    }
} 

//   把中缀表达式转换为后缀表达式,返回后缀表达式的长度(包括空格)
void postfix(char pre[] ,char post[],int &n)
{
    int i = 0 ,j=0;
    SeqStack<char> stack;
    stack.init();       // 初始化存储操作符的栈  

    stack.Push(‘#‘);    // 首先把结束标志‘#’放入栈底  

    while(pre[i]!=‘#‘)
    {
        if((pre[i]>=‘0‘ && pre[i] <=‘9‘)||pre[i] ==‘.‘) // 遇到数字和小数点直接写入后缀表达式
        {
            post[j++] = pre[i];
            n++;
        }
        else if (pre[i]==‘(‘)   // 遇到“(”不用比较直接入栈
            stack.Push(pre[i]);
        else if(pre[i] ==‘)‘)  // 遇到右括号将其对应左括号后的操作符(操作符栈中的)全部写入后缀表达式
        {
            while(stack.GetTop()!=‘(‘)
           {
               post[j++] = stack.Pop();
               n++;
            }
           stack.Pop(); // 将“(”出栈,后缀表达式中不含小括号
        }
       else if (isoperator(pre[i]))
        {
            post[j++] = ‘ ‘; // 用空格分开操作数(
           n++;
            while(priority(pre[i]) <= priority(stack.GetTop()))
            {
                // 当前的操作符小于等于栈顶操作符的优先级时,将栈顶操作符写入到后缀表达式,重复此过程
                post[j++] = stack.Pop();
               n++;
            }  

            stack.Push(pre[i]); // 当前操作符优先级大于栈顶操作符的优先级,将该操作符入栈
        }  

       i++;
    }
    while(stack.top) // 将所有的操作符加入后缀表达式
    {
       post[j++] = stack.Pop();
       n++;
   }
}  

double read_number(char str[],int *i)
{
   double x=0.0;
    int k = 0;
   while(str[*i] >=‘0‘ && str[*i]<=‘9‘)  // 处理整数部分
    {
        x = x*10+(str[*i]-‘0‘);
        (*i)++;
    }  

    if(str[*i]==‘.‘) // 处理小数部分
   {
        (*i)++;
       while(str[*i] >= ‘0‘&&str[*i] <=‘9‘)
        {
         x = x * 10 + (str[*i]-‘0‘);
           (*i)++;
            k++;
        }
    }
    while(k!=0)
    {
        x /= 10.0;
        k--;
   }  

   return x;
}  

double postfix_value(char post[])
{
    SeqStack<double> stack;    // 操作数栈
    stack.init();  

    int i=0 ;
   double x1,x2;  

   while(post[i] !=‘#‘)
    {
       if(post[i] >=‘0‘ && post[i] <=‘9‘)
           stack.Push(read_number(post,&i));
        else if(post[i] == ‘ ‘)
            i++;
        else if (post[i] ==‘+‘)
        {
            x2 = stack.Pop();
            x1 = stack.Pop();
            stack.Push(x1+x2);
            i++;
        }
        else if (post[i] ==‘-‘)
        {
            x2 = stack.Pop();
            x1 = stack.Pop();
            stack.Push(x1-x2);
            i++;
        }
        else if (post[i] ==‘*‘)
        {
            x2 = stack.Pop();
          x1 = stack.Pop();
            stack.Push(x1*x2);
           i++;
        }
        else if (post[i] ==‘/‘)
        {
            x2 = stack.Pop();
           x1 = stack.Pop();
            stack.Push(x1/x2);
            i++;
        }
    }
    return stack.GetTop();
}  
//main.cpp
#include "PrefixToPostfix.h"
#include"expseqstack.h"
#include <iostream>
using namespace std;  

void main()
{
    SeqStack<int> stack ;
   stack.init();  

    //char pre[] ="22/(5*2+1)#";
    char exp[100];
    cout << "输入表达式(中缀,以#结束):";
    cin >> exp;  

   char post[100] ;
    //cout <<"中缀表达式为:"<< pre << endl;  

    int n =0;           // 返回后缀表达式的长度
   postfix(exp,post,n);
    cout <<"后缀表达式为:";
   for( int i =0 ;i < n ;i++)
       cout << post[i] ;  

    cout << "\n由后缀表达式计算出的数值结果:  ";
   cout << postfix_value(post) << endl;  

   system("pause");
}  
时间: 2024-12-28 17:49:29

数据结构 栈的应用 --表达式求值的相关文章

栈应用二(表达式求值)

问题;设计一个程序,演示用算符优先法对算术表达式求值的过程.利用算符优先关系,实现对算术四则混合运算表达式的求值.(1)输入的形式:表达式,例如3+2*6-4     包含的运算符只能有'+' .'-' .'*' .'/'(目前还不兼容括号) :(2)输出的形式:运算结果,例如3+2*6-4=11: (3)程序所能达到的功能:对表达式求值并输出:示例:①3+2*6-4 ②30+20*6-80 ③2*7-3*5-3 思路:1.程序扫描表达式,一个一个的扫描2.当发现这个字符是数字的时候,直接入数栈

栈的应用——表达式求值

表达式求值是程序设计语言编译中的一个基本问题,它的实现就是对“栈”的典型应用.本文针对表达式求值使用的是最简单直观的算法“算符优先法”. 本文给出两种方式来实现表达式求值,方式一直接利用中缀表达式求值,需要用到两个栈,操作数栈和操作符栈.首先置操作数栈为空栈, 操作符栈仅有“#”一个元素.依次读入表达式中的每个字符,若是操作数则进操作数栈,若是操作符则和操作符栈的栈顶运算符比较优先权作相应操作,直至整个表达式求值完毕.方式二首先把中缀表达式转换为后缀表达式并存储起来,然后利用读出的后缀表达式完成

数据结构(7)----栈与队列之栈的应用四则运算表达式求值

栈与队列之栈的应用四则运算表达式求值 栈在四则运算表达式求值的应用为逆波兰表达式(后缀表达式) 普通算式(中缀表达式):9 + (3 - 1) * 3 + 10 / 2     ---(1) 逆波兰表达式(后缀表达式):9 3 1 - 3 * + 10 2 /         ---(2) 1:逆波兰表达式的计算规则 从左到右遍历表达式的每个数字和符号,遇到数字就进栈,遇到符号,就将处于栈顶的两个数字出栈,进行运算,再把运算结果进栈,一直到最终获得结果.接下来我们以(2)式为例:

将中缀表达式转换为后缀表达式,然后利用栈对表达式求值。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js.js"></script> </head> <body> 输入中缀表达式空格分隔 例如 2 + 3 <input type=

c语言:表达式求值实现(包含加减乘除括号)

这道题不难,但是当你认真去编代码的时候,还是要考虑好多细节,所以不能只停留在看懂的层面上,不去实践你永远不知道你到底掌握了没有,加油! 之前的表达式求值不包括括号运算,现将改进后的代码和源代码粘在上面,便于以后的复习. 一.不包括括号运算 #include<iostream> #include<stdio.h> #include<stdlib.h> #include<string> #include<math.h> #define STACK_I

数据结构算法C语言实现(八)--- 3.2栈的应用举例:迷宫求解与表达式求值

一.简介 迷宫求解:类似图的DFS.具体的算法思路可以参考书上的50.51页,不过书上只说了粗略的算法,实现起来还是有很多细节需要注意.大多数只是给了个抽象的名字,甚至参数类型,返回值也没说的很清楚,所以很多需要自己揣摩.这也体现了算法和程序设计语言的特点,算法更侧重本质的描述,而任何编程语言都要照顾到实现的细节以及数据类型等语法方面的需求. 表达式求值: [编码中....] 二.头文件 迷宫求解: 1 //3_2_maze.h 2 /** 3 author:zhaoyu 4 email:[em

C++表达式求值(利用数据结构栈)

唉,刚刚用C++又又一次写了一个较完好的表达式求值程序,最后精简后程序还不到100行.这不经让我 想到了大一上学期刚学c语言时自己费了好大的劲,写了几百行并且功能还不是非常齐全(当时还不能计算有括号的表 达式)的简单计算器程序.刚把两个程序对照了一下.感触还是挺深的,同一时候也再一次体现了数据结构在程序设计 中的重要性. 曾经的那个程序有漏洞并且逻辑复杂,所以就不提了,仅仅说说如今改进后的程序,其思想主要是用到了 栈先进后出的数据结构.在该程序中建有两个栈:一个用于存储运算符,还有一个用于存储操

11、蛤蟆的数据结构笔记之十一栈的应用之表达式求值实现

11.蛤蟆的数据结构笔记之十一栈的应用之表达式求值实现 本篇名言:"人生不售来回票,一旦动身,绝不能复返." 继续栈应用实现,这次是来看下表达式求值的栈实现. 欢迎转载,转载请标明出处: 1.  表达式求值 表达式求值是设计语言编译中的一个基本问题,它的实现是栈应用的又一个典型例子. 任何一个表达式都是由操作数(Operand).运算符(operator)和界限符(delimiter)组成. 操作数可以是常数也可以是变量或变量的标识符. 运算符可以分为算术运算符.关系运算符和逻辑运算符

表达式求值(数据结构书上栈的应用之一)

主要内容:表达式求值,提交nyoj通过... 思路:主要就是一个开两个栈,然后一个操作符栈,一个操作数栈.. 我的代码如下(比较简洁): /***** Author Gery ******/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<vector> #include<cmath&