表达式二叉树(C++实现,实现了通过前缀,中缀,后缀表达式构建二叉树)

学数据结构时的上机作业,花了半天时间写的。

问题描述:

1、对于任意给出的前缀表达式(不带括号)、中缀表达式(可以带括号)或后缀表达式(不带括号),能够在计算机内部构造出一棵表达式二叉树,并且图示出来(图形的形式)。

2、对于构造好的内部表达式二叉树,按照用户的要求输出相应的前缀表达式(不带括号)、中缀表达式(可以带括号,但不允许冗余括)或后缀表达式(不带括号)。

 代码

展开
  1 //表达式二叉树
  2 //作者:王锦
  3 //邮箱:jinksw@vip.qq.com
  4 
  5 #include "stdafx.h"
  6 #include <stack>
  7 #include <utility>
  8 #include <iostream>
  9 #include <sstream>
 10 #include <queue>
 11 #include <cmath>
 12 #include <list>
 13 using namespace std;
 14 
 15 
 16 //二叉树结点类
 17 template<class T>
 18 class BinaryTreeNode
 19 {
 20 private:
 21     T value;
 22     BinaryTreeNode<T> *leftChild;
 23     BinaryTreeNode<T> *rightChild;
 24 public:
 25     BinaryTreeNode(){leftChild = NULL,rightChild = NULL;};
 26     BinaryTreeNode(const T&mValue);
 27     BinaryTreeNode(const T&mValue,BinaryTreeNode<T> *mLeftChild,BinaryTreeNode *mRightChild);
 28     
 29     void setValue(const T&mValue);
 30     T getValue()const;
 31     
 32     BinaryTreeNode<T> * getLeftChild()const;
 33     BinaryTreeNode<T> * getRightChild()const;
 34     void setLeftChild(BinaryTreeNode<T> *leftChild);
 35     void setRightChild(BinaryTreeNode<T> *rightChild);
 36 
 37     bool isLeaf()const;
 38 };
 39 template<class T>
 40 BinaryTreeNode<T>::BinaryTreeNode(const T&mValue)
 41 {
 42     value = mValue;
 43     leftChild = rightChild = NULL;
 44 }
 45 
 46 template<class T>
 47 BinaryTreeNode<T>::BinaryTreeNode(const T&mValue,BinaryTreeNode<T> *mLeftChild,BinaryTreeNode *mRightChild)
 48 {
 49     value = mValue;
 50     leftChild = mLeftChild;
 51     rightChild = mRightChild;
 52 }
 53 
 54 template<class T>
 55 T BinaryTreeNode<T>::getValue()const//得到该结点的值
 56 {
 57     return value;
 58 }
 59 
 60 template<class T>
 61 BinaryTreeNode<T>* BinaryTreeNode<T>::getLeftChild()const//得到左子结点
 62 {
 63     return leftChild;
 64 }
 65 
 66 template<class T>
 67 BinaryTreeNode<T>* BinaryTreeNode<T>::getRightChild()const//得到右子结点
 68 {
 69     return rightChild;
 70 }
 71 
 72 template<class T>
 73 void BinaryTreeNode<T>::setLeftChild(BinaryTreeNode<T> *leftChild)//设置左子结点
 74 {
 75     this->leftChild = leftChild;
 76 }
 77 
 78 template<class T>
 79 void BinaryTreeNode<T>::setRightChild(BinaryTreeNode<T> *rightChild)//设置右子结点
 80 {
 81     this->rightChild = rightChild;
 82 }
 83 
 84 template<class T>
 85 void BinaryTreeNode<T>::setValue(const T&mValue)//设置该结点的值
 86 {
 87     value = mValue;
 88 }
 89 
 90 template<class T>
 91 bool BinaryTreeNode<T>::isLeaf()const//是否为树叶
 92 {
 93     return leftChild == NULL && rightChild == NULL;
 94 }
 95 
 96 class ExpressionBinaryTree
 97 {
 98 private:
 99     BinaryTreeNode<string> *root;
100     void clear()
101     {
102         if(root == NULL) 
103             return;
104         recursionDeleteAll(root);
105     };//调用内部递归函数清空二叉树,以及释放空间
106     bool aIsGreaterOrEqualThanB(char a,char b);//工具方法,用于比较a,b优先级
107     int getHeight(BinaryTreeNode<string> *root);//求树的高度
108     void printBlank(int n);//工具方法,打印n个空格
109     void printInRightFormat(string value);//按照格式打印,以便对齐
110     void recursionPrintPreffixE(BinaryTreeNode<string> *root);//递归调用打印前缀表达式
111     void recursionPrintSuffixE(BinaryTreeNode<string> *root);//递归调用打印后缀表达式
112     bool shouldPrintLeftBracket(const stack<BinaryTreeNode<string>*> &nodeStack ,BinaryTreeNode<string> *pointer,int leftOrRight);//用于输出中缀表达式时判断是否需要输出左括号
113     void recursionDeleteAll(BinaryTreeNode<string> *root);
114 public:
115     ExpressionBinaryTree(){root = NULL;};
116     ~ExpressionBinaryTree(){clear();};
117     void buildBTreeByPreffixE();//以前缀表达式构建二叉树
118     void buildBTreeByInfixE();//以中缀表达式构建二叉树
119     void buildBTreeBySuffixE();//以后缀表达式构建二叉树
120     void printEBTree();//打印二叉树字符图
121     void printPreffixE(){recursionPrintPreffixE(root); cout << endl;}//将递归调用封装,只留给用户打印接口
122     void printSuffixE(){recursionPrintSuffixE(root); cout << endl;}//将递归调用封装,只留给用户打印接口
123     void printInfixE();
124     static const int LEFT = 0;//为左子结点
125     static const int RIGHT = 1;//为右子结点
126 
127 };
128 
129 bool ExpressionBinaryTree::aIsGreaterOrEqualThanB(char a,char b)
130 {
131     switch (a)
132     {
133     case '*':
134     case '/':
135         return true;
136     case '+':
137     case '-':
138         if(b == '*' || b == '/')
139             return false;
140         return true;
141     case '(':
142         return false;
143     }
144     return false;
145 }
146 
147 int ExpressionBinaryTree::getHeight(BinaryTreeNode<string> *root)//求树的高度
148 {
149     if(root == NULL)
150         return 0;
151     int left = getHeight(root->getLeftChild());
152     int right = getHeight(root->getRightChild());
153     return left > right ? left+1 : right+1;
154 }
155 
156 void ExpressionBinaryTree::printBlank(int n)
157 {
158     for(int i = 0;i < n;++i)
159         cout << " ";
160 }
161 
162 void ExpressionBinaryTree::printInRightFormat(string value)//按照格式打印,以便对齐
163 {
164     switch (value.length())
165     {
166     case 1://如果就1个字符,则在两端打印空格,以便对齐
167         cout << " ";
168         cout << value << " ";
169         break;
170     case 2://如果2个字符,则在其后补一个空格,以便对齐
171         cout << value << " ";
172         break;
173     case 3:
174         cout << value;//如果3个字符,则不用补空格
175         break;
176     }
177 }
178 
179 void ExpressionBinaryTree::recursionPrintPreffixE(BinaryTreeNode<string> * root)//递归调用打印前缀表达式
180 {
181     if(root == NULL)
182         return;
183     cout << root->getValue() << " ";
184     recursionPrintPreffixE(root->getLeftChild());
185     recursionPrintPreffixE(root->getRightChild());
186 }
187 
188 void ExpressionBinaryTree::recursionPrintSuffixE(BinaryTreeNode<string> * root)//递归调用打印后缀表达式
189 {
190     if(root == NULL)
191         return;
192     recursionPrintSuffixE(root->getLeftChild());
193     recursionPrintSuffixE(root->getRightChild());
194     cout << root->getValue() << " ";
195 }
196 
197 bool ExpressionBinaryTree::shouldPrintLeftBracket(const stack<BinaryTreeNode<string> *> &nodeStack ,BinaryTreeNode<string> *pointer ,int leftOrRight)//是否应该添加左括号
198 {
199     if(nodeStack.empty())
200         return false;
201     if(pointer == NULL)
202         return false;
203     char a = nodeStack.top()->getValue().c_str()[0];//a b 为栈中父子关系的两个结点值得首字母(为了区分是数字还是操作符)
204     char b = pointer->getValue().c_str()[0];
205     if(b >= '0' && b <= '9')//如果是数字,则不用打括号
206         return false;
207     if(leftOrRight == LEFT)//如果pointer是左结点
208     {
209         switch (a)
210         {
211         case '*':
212         case '/':
213             if(b == '*' || b == '/')
214                 return false;
215             return true;
216         case '+':
217         case '-':
218             return false;
219         }
220     }
221     else if(leftOrRight == RIGHT)//如果pointer是右结点
222     {
223         switch (a)
224         {
225         case '*':
226         case '/':
227             return true;
228         case '+':
229         case '-':
230             if(b == '+' || b == '-')
231                 return true;
232             return false;
233         }
234     }
235     return false;
236 }
237 
238 void ExpressionBinaryTree::recursionDeleteAll(BinaryTreeNode<string> *root)
239 {
240     if(root->getLeftChild() != NULL)
241         recursionDeleteAll(root->getLeftChild());
242     if(root->getRightChild() != NULL)
243         recursionDeleteAll(root->getRightChild());
244     delete root;
245 }
246 
247 void ExpressionBinaryTree::buildBTreeByPreffixE()
248 {
249     clear();
250     root = new BinaryTreeNode<string>();
251     char c;
252     cout << "->请输入前缀表达式,以=结尾." << endl;
253     cout << "->:";
254     cin >> c;
255     stack<BinaryTreeNode<string> *> parentStack;//用于保存存放父结点
256     BinaryTreeNode<string> *pointer = root;//用于指向下一个保存数据的结点
257     string blankStr = "";
258     double tempDouble = 0;
259     string tempStr;//用于输入流,将浮点数转换成字符串
260     while(c != '=')
261     {
262         switch (c)
263         {
264         case '+':
265         case '-':
266         case '*':
267         case '/':
268             pointer->setValue(c+blankStr);//设置当前结点的值
269             pointer->setLeftChild(new BinaryTreeNode<string>());//生成左结点
270             parentStack.push(pointer);
271             pointer = pointer->getLeftChild();
272             break;
273         default:
274             cin.putback(c);
275             cin >> tempDouble;
276             stringstream sss;
277             sss << tempDouble;
278             sss >> tempStr;
279             pointer->setValue(tempStr);
280 
281             pointer = parentStack.top();
282             while(pointer->getRightChild()!=NULL)
283             {
284                 parentStack.pop();//找到按前序遍历的下一个结点
285                 if(parentStack.empty())
286                     break;
287                 pointer = parentStack.top();
288             }
289             if(parentStack.empty())//如果此时栈空则表明表达式已经构建完成
290                 break;
291             pointer->setRightChild(new BinaryTreeNode<string>());//找到了按前序遍历的下一个结点位置并生成结点
292             pointer = pointer->getRightChild();
293             break;
294         }
295         cin >> c;
296     }
297 
298 }
299 
300 void ExpressionBinaryTree::buildBTreeByInfixE()//构造中缀表达式二叉树
301 {
302     clear();
303     root = new BinaryTreeNode<string>();
304     char c;
305     cout << "->请输入中缀表达式,以=结尾." << endl;
306     cout << "->:";
307     cin >> c;
308     stack<BinaryTreeNode<string> *> opd;//操作数栈 //为了方便统一管理,操作数和操作符全部定义为string类型
309     stack<string> opt;//操作符栈
310     double tempDouble = 0;
311     string tempStr;//用于输入流,将浮点数转换成字符串
312     string blankStr = "";
313     while(c != '=')
314     {
315         switch (c)
316         {
317         case '+':
318         case '-':
319         case '*':
320         case '/':
321             while(!opt.empty() && aIsGreaterOrEqualThanB(opt.top().c_str()[0],c))//如果栈顶操作符优先级高于读入操作符优先级,则表名应该先计算栈顶操作符
322             {
323                 BinaryTreeNode<string> *secondOpd = opd.top();
324                 opd.pop();
325                 BinaryTreeNode<string> *firstOpd = opd.top();
326                 opd.pop();//从操作数栈取出两个操作数
327                 opd.push(new BinaryTreeNode<string>(opt.top(),firstOpd,secondOpd));//将操作数和操作符组成一个新结点存入栈中
328                 opt.pop();
329             }            
330             opt.push(c + blankStr);//将读入操作符入栈
331             break;
332         case '(':
333             opt.push(c + blankStr);//遇到左括号直接入栈
334             break;
335         case ')':
336             while(!opd.empty() && opt.top().c_str()[0] != '(')//为了防止冗赘括号,但未检测括号不匹配
337             {
338                 BinaryTreeNode<string> *secondOpd = opd.top();
339                 opd.pop();
340                 BinaryTreeNode<string> *firstOpd = opd.top();
341                 opd.pop();//从操作数栈取出两个操作数
342                 opd.push(new BinaryTreeNode<string>(opt.top(),firstOpd,secondOpd));//将操作数和操作符组成一个新结点存入栈中
343                 opt.pop();
344             }
345             opt.pop();//将左括号出栈
346             break;
347         default://如果是操作数,直接包装成结点入栈
348             cin.putback(c);
349             cin >> tempDouble;
350             stringstream sss;
351             sss << tempDouble;
352             sss >> tempStr;
353             opd.push(new BinaryTreeNode<string>(tempStr));
354             break;
355         }
356         cin >> c;
357     }
358     while(!opt.empty() && aIsGreaterOrEqualThanB(opt.top().c_str()[0],c))//如果栈顶操作符优先级高于读入操作符优先级,则表名应该先计算栈顶操作符
359     {
360         BinaryTreeNode<string> *secondOpd = opd.top();
361         opd.pop();
362         BinaryTreeNode<string> *firstOpd = opd.top();
363         opd.pop();//从操作数栈取出两个操作数
364         opd.push(new BinaryTreeNode<string>(opt.top(),firstOpd,secondOpd));//将操作数和操作符组成一个新结点存入栈中
365         opt.pop();
366     }                
367     root = opd.top();//此时操作数栈中唯一元素即为根元素
368     opd.pop();
369 }
370 
371 void ExpressionBinaryTree::buildBTreeBySuffixE()
372 {
373     clear();
374     char c;
375     cout << "->请输入后缀表达式,以=结尾." << endl;
376     cout << "->:";
377     cin >> c;
378     stack<BinaryTreeNode<string> *> opdStack;//抽象意义上为操作数栈,但实际为操作数和操作符构成的结点栈
379     double tempDouble = 0;
380     string tempStr;//用于输入流,将浮点数转换成字符串
381     string blankStr = "";
382     while(c != '=')
383     {
384         switch (c)
385         {
386         case '+':
387         case '-':
388         case '*':
389         case '/':
390             {
391             BinaryTreeNode<string> *secondOpd = opdStack.top();
392             opdStack.pop();
393             BinaryTreeNode<string> *firstOpd = opdStack.top();
394             opdStack.pop();
395             opdStack.push(new BinaryTreeNode<string>(c+blankStr,firstOpd,secondOpd));
396             break;
397             }
398         default:
399             cin.putback(c);
400             cin >> tempDouble;
401             stringstream sss;
402             sss << tempDouble;
403             sss >> tempStr;
404             opdStack.push(new BinaryTreeNode<string>(tempStr));
405             break;
406         }
407         cin >> c;
408     }
409     root = opdStack.top();//此时操作数栈中唯一元素即为根元素
410     opdStack.pop();
411 }
412 
413 void ExpressionBinaryTree::printEBTree()
414 {
415     int height = getHeight(root);
416     int headIndentation;//行首缩进空格数
417     int InIndentation;//行中单位数据间隔空格数
418     queue<BinaryTreeNode<string> *> nodeQueue;//结点队列
419     nodeQueue.push(root);//将根结点入队列以便第一次操作
420     BinaryTreeNode<string> *pointer;
421     for(int i = 1;i <= height;++i)
422     {
423         headIndentation = (int)2*pow(2.0,double(height)-i)-2;//根据层数获得行首缩进空格数
424         printBlank(headIndentation);
425         InIndentation = (int)2*pow(2.0,double(height)-i+1)-3;//根据高度和层数计算行中单位数据间隔空格数
426         for(int j = 0;j < pow(2.0,double(i)-1)&&!nodeQueue.empty();++j)//遍历第i层结点
427         {    
428             pointer = nodeQueue.front();
429             if(pointer == NULL)//如果是空,则直接输行中单位数据间隔空格数+3个空格(数据占3位,无数据则用空格补全)
430             {
431                 printBlank(InIndentation+3);
432                 nodeQueue.pop();
433                 nodeQueue.push(NULL);
434                 nodeQueue.push(NULL);//向队列内加入两个空子树,当作占位符,以便在无结点的地方输出空格
435             }
436             else
437             {
438                 printInRightFormat(pointer->getValue());
439                 printBlank(InIndentation);
440                 nodeQueue.pop();
441                 nodeQueue.push(pointer->getLeftChild());//左右子树入队列
442                 nodeQueue.push(pointer->getRightChild());
443             }        
444         }
445         cout << endl;
446     }
447 }
448 
449 void ExpressionBinaryTree::printInfixE()
450 {
451     stack<BinaryTreeNode<string> *> nodeStack;//结点栈,遍历使用
452     BinaryTreeNode<string> *pointer = root;
453     list<BinaryTreeNode<string> *> nodeList;//用于记录在哪些元素被输出之后要输出反括号
454     while(!nodeStack.empty() || pointer != NULL)
455     {
456         while(pointer != NULL)//一直向左子结点走,找到左子结点时,经过的结点已全部入栈
457         {
458             if(shouldPrintLeftBracket(nodeStack,pointer,LEFT))//如果应该添加左括号,为左子结点的情况下
459             {
460                 BinaryTreeNode<string> * temp = pointer->getRightChild();//找到应该在输出哪个结点后输出右括号
461                 while(temp->getRightChild() != NULL)
462                     temp = temp->getRightChild();
463                 nodeList.push_back(temp);//将该位置放入序列中,供查询使用
464                 cout << "(";
465             }
466             nodeStack.push(pointer);
467             pointer = pointer->getLeftChild();
468         }
469         cout << nodeStack.top()->getValue();//输出结点 
470         list<BinaryTreeNode<string> *>::iterator it = find(nodeList.begin(),nodeList.end(),nodeStack.top());
471         while(it != nodeList.end())//若栈顶结点(即当前输出结点)为前面记录的应该输出右括号的结点时,输出右括号,可能有多个右括号需要输出,所以循环
472         {
473             cout << ")";
474             nodeList.erase(it);
475             it = find(nodeList.begin(),nodeList.end(),nodeStack.top());
476         }
477         pointer = nodeStack.top()->getRightChild();//所有左结点已经走完,向右走一个
478         if(shouldPrintLeftBracket(nodeStack,pointer,RIGHT))//如果应该添加左括号,为右子结点的情况下
479         {
480             BinaryTreeNode<string> * temp = pointer->getRightChild();
481                 while(temp->getRightChild() != NULL)
482                     temp = temp->getRightChild();
483                 nodeList.push_back(temp);
484             cout << "(";
485         }
486         nodeStack.pop();
487     }
488     cout << endl;
489 }
490 
491 void printPrompting()//输出提示信息
492 {
493     cout << "->请选择要输入的表达式种类:" << endl;
494     cout << "->1:前缀表达式.2:中缀表达式.3:后缀表达式.(输入q退出)" << endl;
495     cout << "->:";
496 }
497 
498 int _tmain(int argc, _TCHAR* argv[])
499 {
500     ExpressionBinaryTree ebt;
501     char c;
502     printPrompting();
503     cin >> c;
504     while(c != 'q')
505     {
506         switch(c)
507         {
508         case '1':
509             ebt.buildBTreeByPreffixE();
510             cout << "----------------------------------------------------" << endl;
511             cout << "->通过前缀表达式构建的二叉树为:" << endl;
512             ebt.printEBTree();
513             break;
514         case '2':
515             ebt.buildBTreeByInfixE();
516             cout << "----------------------------------------------------" << endl;
517             cout << "->通过中缀表达式构建的二叉树为:" << endl;
518             ebt.printEBTree();
519             break;
520         case '3':
521             ebt.buildBTreeBySuffixE();
522             cout << "----------------------------------------------------" << endl;
523             cout << "->通过后缀表达式构建的二叉树为:" << endl;
524             ebt.printEBTree();
525             break;
526         default:
527             cout << "->序号选择错误,请重新输入。" << endl;
528             printPrompting();
529             cin >> c;
530             continue;
531         }
532         cout << "->此表达式二叉树对应的前缀表达式为:" << endl;
533         cout << "->";
534         ebt.printPreffixE();
535         cout << "->此表达式二叉树对应的中缀表达式为:" << endl;
536         cout << "->";
537         ebt.printInfixE();
538         cout << "->此表达式二叉树对应的后缀表达式为:" << endl;
539         cout << "->";
540         ebt.printSuffixE();
541         cout << "----------------------------------------------------" << endl;
542         printPrompting();
543         cin >> c;
544     }
545 }

 

posted @ 2013-04-28 12:12  Jinks  阅读(3790)  评论(0编辑  收藏  举报