功能:输入一个中缀表达式的值(+ - * / ( ) )然后得出计算结果
设计:1 第一步将中缀表达式转换为后缀表达式,每一个表达式都对应一个符号表达式数,中缀表达式是对数做中序遍历,而后缀表达式则是对次数做后缀遍历,学过数据结构的应该对此很熟悉了,借助堆栈可以轻松实现此点,在此我要说明的一点是,由于一个整数可能会占一个字符,比如“456”就占了3位,所以为了标识每个数在转换为后缀表达式后在每个数后面都加上了一个“#”,譬如“16 +28”转换后即为“16#28#+”
2第二步相对来说就简单很多了,利用堆栈对后序表达式进行计算就可以了
下面给出源码
首先是头文件,里面是自己用链表实现的一个堆栈,很简单,在此不多做解释
1 #ifndef STACK_H
2 #define STACK_H
3
4 template<typename T>
5 class Stack;
6
7 template<typename T>
8 class SNode
9 {
10 friend class Stack<T>;
11 private:
12 T m_Data;
13 SNode *m_pNext;
14 };
15
16 template<typename T>
17 class Stack
18 {
19 public:
20 Stack();
21 ~Stack();
22 public:
23 void Push(T data);
24 T Pop();
25 bool IsEmpty();
26 T GetTop();
27 private:
28 SNode<T> *m_pTop;
29 };
30
31 template<typename T>
32 Stack<T>::Stack()
33 {
34 m_pTop=new SNode<T>;
35 m_pTop->m_pNext=NULL;
36 }
37
38 template<typename T>
39 void Stack<T>::Push(T data)
40 {
41 SNode<T> *pNode=new SNode<T>;
42 m_pTop->m_Data=data;
43 pNode->m_pNext=m_pTop;
44 m_pTop=pNode;
45 }
46
47 template<typename T>
48 T Stack<T>::Pop()
49 {
50 SNode<T> *pNode=m_pTop->m_pNext;
51 if(pNode==NULL)
52 {
53 std::cout<<"Stack is empty"<<std::endl;
54 exit(0);
55 }
56 m_pTop->m_pNext=pNode->m_pNext;
57 T data=pNode->m_Data;
58 delete pNode;
59 pNode=NULL;
60 return data;
61 }
62
63 template<typename T>
64 bool Stack<T>::IsEmpty()
65 {
66 return m_pTop->m_pNext==NULL;
67 }
68
69 template<typename T>
70 T Stack<T>::GetTop()
71 {
72 SNode<T> *pNode=m_pTop->m_pNext;
73 return pNode->m_Data;
74 }
75 template<typename T>
76 Stack<T>::~Stack()
77 {
78 SNode<T> *pNode=m_pTop->m_pNext,*pCur;
79 while(pNode!=NULL)
80 {
81 pCur=pNode;
82 pNode=pNode->m_pNext;
83 delete pCur;
84 }
85 }然后是两个函数,第一个函数将中序表达式换为后序表达式,第二个对后序表达式进行计算
这是第一个函数
此函数基于如下算法
顺序的读入中序表达式,若遇到字符为操作数时则直接输出,并接着读下一字符,若单词为运算符时,取栈顶变量与当前变量的优先级做比较,若栈顶元素的优先级较高或相等,则栈顶元素退栈并输出到后序表达式中,接着新的栈顶变量与之比较。若栈顶元素优先级低,则该元素进栈,接着读下一字符。以上情况均需考虑有括号存在的情况。
需要说明的是isdigit()函数功能为判断其形参是否为数字,是则返回非零值,否则返回零。
1 std::string InToPost(std::string infix)
2 {
3 Stack<char> stack;
4 char current = 0;//读入的字符
5 std::string postfix;//写入后缀表达式的字符串
6
7 std::map<char,int> priority;//运算符号优先级表
8 priority['+'] = 0;
9 priority['-'] = 0;
10 priority['*'] = 1;
11 priority['/'] = 1;
12
13 for(int i = 0;i<infix.length();++i)//逐个读取中缀表达式字符串中的字符
14 {
15 current =infix[i];
16 if(isdigit(current))//如果是数字直接输出
17 postfix.push_back(current);
18 switch(current)
19 {
20 case '+':
21 case '-':
22 case '*':
23 case '/':
24 if(infix[i-1] != ')') postfix.push_back('#');//如果运算符的前一项不是右括号则说明前一个数字输入完毕,用#标识前面几个字符组成一个数字
25 if(!stack.IsEmpty())//比较目前符号与栈顶符号优先级,低于则出栈,并输出字符串
26 {
27 char tempTop=stack.GetTop();
28 while(tempTop != '(' &&priority[current]<=priority[tempTop])
29 {
30 char tempOut;
31 tempOut=stack.Pop();
32 postfix.push_back(tempOut);
33 if(stack.IsEmpty())
34 break;
35 tempTop=stack.GetTop();
36 }
37 }
38 stack.Push(current);//符号全部出栈或者遇到了'('或者大于栈顶符号的优先级,将新符号压入栈中
39 break;
40 case '.':
41 postfix.push_back(current);
42 break;
43 case '(':
44 stack.Push(current);//左括号直接入栈
45 break;
46 case ')':
47 postfix.push_back('#');//右括号说明前方数字输入完成,标识一下
48 char tempTop;
49 tempTop=stack.GetTop();
50 while(tempTop !='(')//直到栈顶元素是左括号才停止循环
51 {
52 char tempOut;
53 tempOut=stack.Pop();
54 postfix.push_back(tempOut);
55 tempTop=stack.GetTop();
56 }
57 char tempOut;
58 tempOut=stack.Pop();
59 break;
60 default:
61 break;
62 }
63 }
64 if(infix[infix.size()-1] != ')') postfix.push_back('#');
65 while(!stack.IsEmpty())
66 {
67 char tempOut=stack.Pop();
68 postfix.push_back(tempOut);
69 }
70 return postfix;
71 }第二个函数利用栈计算表达式的值并返回
1 float Compute(std::string s)
2 {
3 Stack<float> stack;
4
5 std::string str;
6 float curr;
7
8 double temNum1;
9 double temNum2;
10 for(std::string::iterator i = s.begin();i<s.end();i++)
11 {
12 if(isdigit(*i))
13 str.push_back(*i);
14 switch(*i)
15 {
16 case '+':
17 temNum1=stack.Pop();
18 temNum2=stack.Pop();
19 stack.Push(temNum2 + temNum1);
20 break;
21 case '-':
22 temNum1=stack.Pop();
23 temNum2=stack.Pop();
24 stack.Push(temNum2 - temNum1);
25 break;
26 case '*':
27 temNum1=stack.Pop();
28 temNum2=stack.Pop();
29 stack.Push(temNum2 * temNum1);
30 break;
31 case '/':
32 temNum1=stack.Pop();
33 temNum2=stack.Pop();
34 stack.Push(temNum2 / temNum1);
35 break;
36 case '.':
37 str.push_back(*i);
38 break;
39 case '#':
40 curr =std::atof(str.c_str());//字符串转换为浮点型
41 str.clear();
42 stack.Push(curr);
43 break;
44 }
45 }
46 curr=stack.Pop();
47 return curr;
48 }以下是测试的结果

















