问题描述与解题思路与我之前用C语言写过的博客一模一样,这里这不过是用面向对象的思想以C++语言的方式再次呈现一遍。
C语言版本:点击打开链接
https://blog.csdn.net/y_16041527/article/details/79835727
So......这里直接上C++的完整代码
注意:这里采用多文件编程、不要将BinaryTree.h头文件和ExpTFTree.cpp文件按照前后顺序直接放到一起,会导致编译错误,分开放。
头文件声明:
//BinaryTree.h #include <iostream> const int MaxSize = 100; using namespace std; //链式二叉树节点的抽象数据类型定义 template <class T> class BinaryTreeNode { public: T data; //数据域 BinaryTreeNode<T> *left, *right; //指向二叉树节点的指针 BinaryTreeNode() {} //无参构造函数 BinaryTreeNode(const T d, BinaryTreeNode<T> *l = NULL, BinaryTreeNode<T> *r = NULL) :data(d), left(l), right(r) {} //给定数据域和指针域的构造函数 }; //表达式二叉树的抽象数据类型定义 template <class T> class ExpTFTree:public BinaryTreeNode<T> { public: BinaryTreeNode<T> *root; //二叉树根节点 T s[MaxSize]; //存储表达式的数组 public: ExpTFTree() { root = NULL; } //构造函数 ~ExpTFTree() //析构函数 { DeleteExpTFTree(root); cout << "释放成功" << endl; } void PerCreateTree(); //前缀表达式建树 void PostCreateTree(); //后缀表达式建树过程 BinaryTreeNode<T>* InCreateTree(T s[], int i, int j); //中缀表达式建树过程 void DispTree(BinaryTreeNode<T> *root); //凹入表示法输出一棵二叉树 void PerOrder(BinaryTreeNode<T> *root); //前序周游给定二叉树 void InOrder(BinaryTreeNode<T> *root); //中序周游 void PostOrder(BinaryTreeNode<T> *root); //后序周游 void DeleteExpTFTree(BinaryTreeNode<T> *root); //删除给定的二叉树 };
Cpp文件
//ExpTFTree.cpp - 表达式二叉树 #include "stdafx.h" #include "BinaryTree.h" #include <string.h> using namespace std; //ExpTFTree类相关成员函数的实现 //删除给定的二叉树 template <class T> void ExpTFTree<T>::DeleteExpTFTree(BinaryTreeNode<T> *root) { if (root) { DeleteExpTFTree(root->left); DeleteExpTFTree(root->right); delete root; root = NULL; } } //凹入表示法输出二叉树 template <class T> void ExpTFTree<T>::DispTree(BinaryTreeNode<T> *root) { cout << "凹入表示法输出一棵二叉树" << endl; BinaryTreeNode<T> *stack[MaxSize], *p; //stack[top]为指针数组,其中每一个元素存放的是指向树节点的指针 int level[MaxSize][2], top, i, n, width = 4; //top为stack栈指针、levle[MaxSize][2]为二维数组,0维度-width(输出空格数)、1维度-不同节点 T type; if (root != NULL) { top = 1; //左节点之前输出(0) stack[top] = root; //根节点入栈 level[top][0] = width; level[top][1] = 2; //2代表根节点 while (top > 0) //栈不为空时,循环继续 { p = stack[top]; //退栈并凹入显示该节点值 n = level[top][0]; switch (level[top][1]) { case 0: type = '0'; //左节点之前输出(0) break; case 1: type = '1'; //右节点之前输出(1) break; case 2: type = 'r'; //根节点之前输入(r) break; } for (i = 1; i <= n; i++) //n为输出的空格数,字符以右对齐显示 cout << " "; cout << p->data << " (" << type << ")"; for (i = n + 1; i <= MaxSize; i += 2) cout << "-"; cout << endl; top--; //根节点出栈 //因为使用的栈、所以先将右子树根入栈,后将左子树根入栈 //然后出栈时,按照后进先出的原则先输出左子树根,后输出右子树根 if (p->right != NULL) { top++; stack[top] = p->right; //将右子树根节点入栈 level[top][0] = n + width; //输出空格数增加width level[top][1] = 1; //1表示是右子树 } if (p->left != NULL) { top++; stack[top] = p->left; //将左子树根节点入栈 level[top][0] = n + width; //输出空格数增加width level[top][1] = 0; //0代表左子树 } } } cout << endl; } //前缀表达式建树 template <class T> void ExpTFTree<T>::PerCreateTree() { cout << "前缀表达式建树" << endl; cout << "前缀表达式:"; cin >> s; int len = strlen(s); // cout << "len:" << len << endl; //计数变量 int i; BinaryTreeNode<T> *p; //临时栈 - 用来存放指向树节点的指针 struct stack { BinaryTreeNode<T> *vec[MaxSize]; int top; }; struct stack q; q.top = 0; //遍历字符串,若为操作数 - 则生成根节点并将指向该根节点的指针入栈、若为运算符 - 则生成节点并在临时栈中弹出两个指向操作数 //节点的指针,并指向该运算符节点并将其入栈 for (i = len - 1; i >= 0; i--) { //为操作符 if (s[i] == '+' || s[i] == '/' || s[i] == '*' || s[i] == '-') { p = new BinaryTreeNode<T>(s[i]); p->left = q.vec[q.top--]; //先弹出的为左节点 p->right = q.vec[q.top--]; //后弹出的为右节点 q.vec[++q.top] = p; //将根节点入栈 } else //s[i]为操作数 { p = new BinaryTreeNode<T>(s[i]); q.vec[++q.top] = p; //将指向操作数节点的指针入栈 } } root = q.vec[q.top--]; //这一步很关键,因为该二叉树的根节点最后被保留在了栈中 } //中缀表达式建树过程 template <class T> BinaryTreeNode<T>* ExpTFTree<T>::InCreateTree(T s[], int i, int j) { BinaryTreeNode<T> *p; int k, flag = 0, pos; //如果i == j,则说明字符串只有一个字符,即为叶子节点、则创建只有一个根节点的二叉树并返回 if (i == j) { p = new BinaryTreeNode<T>(s[i]); return p; } //以下是 i != j的情况 //从左往右找最后一个+或-,先找+或-为了体现先乘除后加减的原则 for (k = i; k <= j; k++) { if (s[k] == '+' || s[k] == '-') { flag = 1; pos = k; } } //若没有+或-,则寻找字符串中最后一个*或/ if (flag == 0) { for (k = 0; k <= j; k++) { if (s[k] == '*' || s[k] == '/') { flag = 1; pos = k; } } } //若flag不等于0,则以pos为界将字符串分为左右两部分,分别对应表达式二叉树的左、右子树 //同样以最后的运算符为根,将串分为两部分 //创建一个根节点、将找到的运算符放入 if (flag != 0) { p = new BinaryTreeNode<T>(s[pos]); p->left = InCreateTree(s, i, pos - 1); //递归调用自身进入其左子树建树过程 p->right = InCreateTree(s, pos + 1, j); //递归调用自身进入其右子树建树过程 return p; } else return NULL; } //后缀表达式建树 template <class T> void ExpTFTree<T>::PostCreateTree() { cout << "后缀表达式建树" << endl; cout << "后缀表达式:"; cin >> s; int len = strlen(s); //表达式长度 int i; BinaryTreeNode<T>* p; //临时栈 - 用来存放指向树节点的指针 struct stack { BinaryTreeNode<T> *vec[MaxSize]; int top; }; struct stack q; q.top = 0; //遍历字符串,若为操作数 - 则生成根节点并将指向该根节点的指针入栈、若为运算符 - 则生成节点并在临时栈中弹出两个指向操作数 //节点的指针,并指向该运算符节点并将其入栈 for (i = 0; i < len; i++) { //为操作符 if (s[i] == '+' || s[i] == '/' || s[i] == '*' || s[i] == '-') { p = new BinaryTreeNode<T>(s[i]); p->right = q.vec[q.top--]; //先弹出的为右节点 p->left = q.vec[q.top--]; //后弹出的为左节点 q.vec[++q.top] = p; //将根节点入栈 } else { //s[i]为操作数 p = new BinaryTreeNode<T>(s[i]); q.vec[++q.top] = p; //将指向操作数节点的指针入栈 } } root = q.vec[q.top--]; //这一步很关键,因为该二叉树的根节点最后被保留在了栈中 } //前序遍历 template <class T> void ExpTFTree<T>::PerOrder(BinaryTreeNode<T>* root) { if (root) { cout << root->data << " "; PerOrder(root->left); PerOrder(root->right); } } //中序遍历 template <class T> void ExpTFTree<T>::InOrder(BinaryTreeNode<T>* root) { if (root) { InOrder(root->left); cout << root->data << " "; InOrder(root->right); } } //后序遍历 template <class T> void ExpTFTree<T>::PostOrder(BinaryTreeNode<T>* root) { if (root) { PostOrder(root->left); PostOrder(root->right); cout << root->data << " "; } } int main() { ExpTFTree<char> A; char s[MaxSize]; cout << "中缀表达式:"; cin >> s; A.root = A.InCreateTree(s, 0, strlen(s) - 1); //中缀表达式建树 A.DispTree(A.root); cout << "前序周游:"; A.PerOrder(A.root); cout << endl; //前序周游 cout << "中序周游: "; A.InOrder(A.root); cout << endl; //中序周游 cout << "后序周游:"; A.PostOrder(A.root); cout << endl; //后序周游 A.PostCreateTree(); //后缀表达式建树 A.DispTree(A.root); A.PerCreateTree(); //前缀表达式建树 A.DispTree(A.root); return 0; }
运行结果:
中缀表达式:a+b*c-e/f
凹入表示法输出一棵二叉树
- (r)------------------------------------------------
+ (0)----------------------------------------------
a (0)--------------------------------------------
* (1)--------------------------------------------
b (0)------------------------------------------
c (1)------------------------------------------
/ (1)----------------------------------------------
e (0)--------------------------------------------
f (1)--------------------------------------------
凹入表示法输出一棵二叉树
- (r)------------------------------------------------
+ (0)----------------------------------------------
a (0)--------------------------------------------
* (1)--------------------------------------------
b (0)------------------------------------------
c (1)------------------------------------------
/ (1)----------------------------------------------
e (0)--------------------------------------------
f (1)--------------------------------------------
前序周游:- + a * b c / e f
中序周游: a + b * c - e / f
后序周游:a b c * + e f / -
后缀表达式建树
后缀表达式:abc*+ef/-
凹入表示法输出一棵二叉树
- (r)------------------------------------------------
+ (0)----------------------------------------------
a (0)--------------------------------------------
* (1)--------------------------------------------
b (0)------------------------------------------
c (1)------------------------------------------
/ (1)----------------------------------------------
e (0)--------------------------------------------
f (1)--------------------------------------------
中序周游: a + b * c - e / f
后序周游:a b c * + e f / -
后缀表达式建树
后缀表达式:abc*+ef/-
凹入表示法输出一棵二叉树
- (r)------------------------------------------------
+ (0)----------------------------------------------
a (0)--------------------------------------------
* (1)--------------------------------------------
b (0)------------------------------------------
c (1)------------------------------------------
/ (1)----------------------------------------------
e (0)--------------------------------------------
f (1)--------------------------------------------
前缀表达式建树
前缀表达式:-+a*bc/ef
凹入表示法输出一棵二叉树
- (r)------------------------------------------------
+ (0)----------------------------------------------
a (0)--------------------------------------------
* (1)--------------------------------------------
b (0)------------------------------------------
c (1)------------------------------------------
/ (1)----------------------------------------------
e (0)--------------------------------------------
f (1)--------------------------------------------
前缀表达式:-+a*bc/ef
凹入表示法输出一棵二叉树
- (r)------------------------------------------------
+ (0)----------------------------------------------
a (0)--------------------------------------------
* (1)--------------------------------------------
b (0)------------------------------------------
c (1)------------------------------------------
/ (1)----------------------------------------------
e (0)--------------------------------------------
f (1)--------------------------------------------
释放成功
请按任意键继续. . .
请按任意键继续. . .