字符串四则运算求值

假定给定一个四则运算字符串:8+7*2 –9/3;那么该表达式的值为19. 但是如何用C/C++程序上实现计算一个字符串表达式呢?一个常用的做法是将表达式的字符串转换为后缀表达式,即:1)表达式8+2,转换为后缀表达式是8 2+;2)表达式8 +3*4,转换为后缀表达式是834*+;

然后通过栈的操作可以求得它们的结果:

2)例为例:

压入8                    

压入3

压入4

遇到*

然后弹出两个字符,即34,进行*的运算,得到12

压入12

遇到+

弹出两个字符,812,进行+的运算,得到20

此时到达后缀表达式的末尾,因此最终的结果是20.

 

 

上面考虑的是简单的情况,比较复杂的情况是:
1、表达式中包含浮点型的数据以及负数

2、表达式中包含“(”和“)”的括号操作

不过以上两种情况都有可以解决的方法:

对于情况1,可以先对字符串表达式进行处理,即定义一个string类的链表,将每个可以作为合法的子串存储到链表上,即比如:-8 + 3.77*2.5 + -3;那么将它转换为的链表就是:

-8

+

3.77

*

2.5

+

-3

然后再将其转换为后缀表达式就可以了。

对于情况2 主需要在转换为后缀表达式时,注意下括号的影响和去除就可以了。

 

那么就总结下字符串表达式求值的方法:

1、  分析字符串中是否存在负数和浮点数,然后将他们依次存入一个叫做substring的链表中,如上面所示;

2、  然后再利用一个list<stirng>存储将要生成的后缀表达式,利用一个stack<string >存储操作符;具体方法如下

1)、遍历substring的链表,如果是操作数直接加入list<string>;如果是操作符,则比较其和前一个操作符的优先级,如果后来的操作符的优先级高于或等于前者,则直接压入栈,如果后来的操作如的优先级低于前者,则弹出前者,并将前者加入list<string>中去。

2)、如果遇到“(”,则将其直接压入操作符栈,以后的的操作符同上处理,知道遇到“)”,则依次弹出“(”和“)”之间的内容。后面依据重复第一步。

3、计算后缀表达式

需要一个栈,即依次遍历后缀表达式的链表list<string>;如果遇到操作数,则直接压栈;如果遇到操作符,则弹出两个操作数,并进行相应的计算;然后将计算结果压入栈;继续遍历,直到到达链表的末尾。

举一个例子,能更清晰的了解其中的过程:

假设字符串表达式是 -7*(8+7)-6*2 + -8;那么它的substring链表是

-7

*

8

+

7

-

6

*

2

+

-8

那么对其做转换为后缀表达式的处理:(红色部分代表后缀表达式的链表,蓝色代表操作符栈)

第一步:将“-7”放入后缀表达式链表,*”压入栈;

第二步:遇到“(”,将其压入栈,并将“8”放入后缀表达式链表;

第三步:遇到“+”,将其压入栈,并将“7放入后缀表达式链表;

第四步:遇到“)”,将栈中的操作符依次放入后缀表达式链表;此时的后缀表达式是:-787+

第五步:遇到“-”,由于“-”的优先级小于之前的“*”,因此“*”退栈并放入后缀表达式链表;然后将“-”压入栈;将“6放入后缀表达式链表;此时的后缀表达式是:-787+*6

第六步:遇到“*”,由于“*”的优先级大于“-”,将其压入栈,并将“2放入后缀表达式链表;

第七步:遇到“+”,由于“+”的优先级小于“*”,因此类似第五步得到的后缀表达式是:

-787+*62*-8+-

 

下面编写C++代码实现字符串的四则运算,在这里假设字符串里出现的都是正整数,即没有负数和浮点数,因此忽略的了第一步的有关substring链表的计算。

#include <iostream>
using namespace std;
#include <stack>
#include <list>
#include <cstring>
#include <queue>
queue<string> substring_queue;
list<string> suffix_list;
stack<string> cal_stack;

void create_substring_list(char *pch)
{
	if(NULL == pch)
	{
		cout<<"str is NULL!"<<endl;
		return;
	}
	list<string> substring_list; //
	while('\0' != *pch)
	{
		string str="";
		str += *pch++;
		substring_list.push_back(str);
	}
    list<string>::iterator iter = substring_list.begin();
	while(iter != substring_list.end())
	{
		substring_queue.push(*iter);
		++iter;
	}
}

void create_suffix_list(queue<string> que)
{
    if(que.empty())
        return;
    string str_temp;
    while(!que.empty())
    {
        str_temp = que.front();
        if(str_temp == "(")
            {
                cal_stack.push(str_temp);
                }
        else if(str_temp == ")")
            {
                while(!cal_stack.empty()&&cal_stack.top()!="(")
                {
                    suffix_list.push_back(cal_stack.top());
                    cal_stack.pop();
                    }
                if(!cal_stack.empty())
                    cal_stack.pop();
                }

        else if(str_temp == "+" ||str_temp == "-")
        {
            if(cal_stack.empty() || cal_stack.top() == "(")
                cal_stack.push(str_temp);
            else
            {
                while(!cal_stack.empty())
                {
                    suffix_list.push_back(cal_stack.top());
                    cal_stack.pop();
                }
                cal_stack.push(str_temp);
                }
        }
        else if(str_temp == "*" || str_temp == "/")
        {
            cal_stack.push(str_temp);
            }
        else
        {
            suffix_list.push_back(str_temp);
            }
        que.pop();
    }
    while(!cal_stack.empty())
    {
        suffix_list.push_back(cal_stack.top());
        cal_stack.pop();
    }
    }
void calculate(list<string> lst)
{
    if(lst.empty())
        return ;
    int num,n1,n2;
    stack<int> int_stack;
    char ch;
    list<string>::iterator iter = lst.begin();
    while(iter != lst.end())
    {
        ch = (*iter).at(0);
        //cout<<ch<<endl;
        switch(ch)
        {
            case '+':
            n1 = int_stack.top();
            int_stack.pop();
            n2 = int_stack.top();
            int_stack.pop();
            num = n1 +n2;
            int_stack.push(num);
            cout<<"+ num  "<<num<<endl;
            break;
            case '-':
            n1 = int_stack.top();
            int_stack.pop();
            n2 = int_stack.top();
            int_stack.pop();
            num = n2-n1;
            int_stack.push(num);
            cout<<"+ num  "<<num<<endl;
            break;
            case '*':
            n1 = int_stack.top();
            int_stack.pop();
            n2 = int_stack.top();
            int_stack.pop();
            num = n1*n2;
            int_stack.push(num);
            cout<<"+ num  "<<num<<endl;
            break;
            case '/':
            n1 = int_stack.top();
            int_stack.pop();
            n2 = int_stack.top();
            int_stack.pop();
            num = n2/n1;
            int_stack.push(num);
            cout<<"+ num  "<<num<<endl;
            break;
            default:
            num = ch-'0';
            cout<<num<<"  shuzi"<<endl;
            int_stack.push(num);
            break;
        }
        ++iter;
        }
    cout<<int_stack.top()<<endl;
    }
int main()
{
	char *pch = "8+7*2-(9+1)";
	create_substring_list(pch);
    /*while(!substring_queue.empty())
    {
        string str = substring_queue.front();
        cout<<str.at(0);
        substring_queue.pop();
        }
	cout<<endl;*/
	create_suffix_list(substring_queue);
    list<string>::iterator iter = suffix_list.begin();
	while(iter != suffix_list.end())
	{
		cout<<*iter;
		++iter;
	}
	cout<<endl;
    calculate(suffix_list);
	return 0;
}

 

以上代码有些冗杂,是因为我想多用几个STL中的数据类型,其实里面很多的都是不必要的操作,比如create_substring_list()函数中:首先将字符串的内容,赋给一个链表,然后再把链表的内容赋给一个队列;其实这里面的链表是多余的,完全可以直接把字符串的内容赋给队列。还有就是代码里面的stack,list和queue都是用string类型实例化的,其实在这里只考虑了简单的0~9的数字的四则运算(不包括浮点和负数),因此完全可以用char类型实例化它们的。这里用string类型只不过是为了以后能处理浮点和负数等类型做准备的。而且还学习下如果把一个char字符转换为string类型:如:char ch = ‘a’; string str; str+= ch;就实现了把char字符转换为string类型了。或者也可以先把char转换为char[],然后将char[]赋给string。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值