大学考试周太忙了,但不管怎样,不要焦虑过度,与其一直在烦躁,不如踏踏实实静下来心,抓紧时间提高效率,总能完成的。升华往往就在这些关键时机,要把握住呀,诸位(づ ̄3 ̄)づ╭❤~
一、思路
建树的思路
- 若已知后缀表达式,建树。算法实现为从左开始向右遍历后缀表达式的元素,新建一个树节点p,值为当前元素的值。如果取到的元素是操作数,直接把p入栈;如果是运算符,从栈中弹出2个节点,把第一个弹出的节点作为p的右子树,第二个弹出的节点作为p的左子树,然后把p入栈。当遍历完逆波兰式时,树的根节点就保存在栈里了。
- 若已知中缀表达式,建树。使用栈操作,需要将其转化为后缀表达式,再执行建树操作,此处不采用此方法。参考网上代码,采用直接对中缀表达式进行处理的方法。
二、处理过程
- 和普通二叉树不同,表达式二叉树的结点私有成员变量包含的结点值是字符数组类型。因此在对结点初始化时需注意赋值条件。当查找到某个表达式字符要作为根结点时,才开始初始化结点类。
- 在完成此次作业过程中,在有个问题的理解上纠结了挺久的。已知算术表达式的中缀或后缀,其算术表达式唯一吗?起初我以为是唯一的(事实上就是唯一的),若已知算术表达式的中缀
a+b*c/d
,想当然解出其后缀表达式abc*+d/
,这样相当于知道了该表达式的中序和后序遍历,然后由中序和后序的遍历结果即可求出唯一的二叉搜索树。然后代入老师给出的题目案例(已知中序和后序遍历的序列及所建的表达式二叉树),也就是代入了中序遍历序列,但ppt上的树和代码跑出的树竟不一样。开始产生疑惑,对比思考后发现,算数表达式是唯一的,只是我想当然把中缀表达式和中序遍历等同化了。
现总结得出结论:中序遍历的序列不一定是中缀表达式,因为遍历序列不包含符号(),如:不同的中缀表达式a+b*c-d-e/f
,a+b*(c-d)-e/f,
但其中序遍历序列是一样的。同样,可推论,仅在知道中序和后序遍历序列情况下,可建立表达式二叉树,但不能得出表达式。
至此,在理解上才完全弄清楚。添加下图,附以说明。
三、代码
eBST.h
#pragma once
#include <iostream>
#include <string>
#include<iomanip>
#include"Node.h"
using namespace std;
class eBST
{
public:
void graphAux(int, Node*);
void preorderAux(Node*);
void inorderAux(Node*);
void postorderAux(Node*);
Node* root;
public:
eBST();
Node* create(char*,int, int);
};
eBST::eBST() :root(0) {}
Node* eBST::create(char x[500], int left, int right)
{
int p = 0, le = left, r = right, as = -1, md = -1, index = 0;
Node* n = root;
while (le < r)
{
if (x[le] < '0' || x[le]>'9')
{
break;
}
le++;
}
//第一个运算符出现在末尾
if (le == r)
cerr << "输入的中缀表达式有误,请重输" << endl;
else
{
le = left; r = right;
//开始遍历运算符
while (le <= r)
{
if (p == 0 && (x[le] == '+' || x[le] == '-'))
{
as = le;
}
else if (p == 0 && (x[le] == '*' || x[le] == '/'))
{
md = le;
}
else if (x[le] == '(')
{
p++;
}
else if (x[le] == ')')
{
p--;
}
le++;
}
//+-*/运算符位置
if (as != -1)
{
n = new Node(x[as]);
n->date[0] = x[as];
n->left = create(x, left, as - 1);
n->right = create(x, as + 1, right);
return n;
}
else if (as == -1 && md != -1)
{
n = new Node(x[md]);
n->date[0] = x[md];
n->left = create(x, left, md - 1);
n->right = create(x, md + 1, right);
return n;
}
else if (as == -1 && md == -1)
{
return create(x, left + 1, right - 1);
}
}
}
//打印二叉树
void eBST::graphAux(int index, Node* n)
{
if (n != NULL)
{
graphAux(index + 8, n->left);
cout << setw(index) << " " << n->date << endl;
graphAux(index + 8, n->right);
}
}
void eBST::inorderAux(Node* n)
{
if (n != NULL)
{
inorderAux(n->left);
cout << n->date << " ";
inorderAux(n->right);
}
}
void eBST::preorderAux(Node* n)
{
if (n != NULL)
{
preorderAux(n->left);
preorderAux(n->right);
cout << n->date << " ";
}
}
void eBST::postorderAux(Node* n)
{
if (n != NULL)
{
postorderAux(n->left);
postorderAux(n->right);
cout << n->date << " ";
}
}
Node.h
#pragma once
#include<iostream>
using namespace std;
class Node
{
public:
Node();
Node(char);
friend class eBST;
char date[50];
Node* left;
Node* right;
};
Node::Node(char d)
{
date[0]=d;
left = NULL;
right = NULL;
}
main.cpp
#include <iostream>
#include"eBST.h"
#include"Node.h"
using namespace std;
int main() {
char x[500];
eBST e;
cout << "输入中缀表达式,注意括号的中英文区别:" << endl;
while (cin>>x)
{
Node* root = e.create(x, 0, strlen(x) - 1);
e.graphAux(0,root );
cout << "前序遍历:";
e.preorderAux(root);
cout << endl;
cout << "中序遍历:";
e.inorderAux(root);
cout << endl;
cout << "后序遍历:";
e.postorderAux(root);
cout << endl;
}
return 0;
}
OK,结束。关于本次代码实操,若小可爱们有疑问或者建议,欢迎下方留言。在此,昨天晚上熬夜时,突然想起一首歌,也不知道为什么,感觉很好听,想安利给大噶!不眠之夜,拜拜┏(^0^)┛