中缀表达式转表达式二叉搜索树


大学考试周太忙了,但不管怎样,不要焦虑过度,与其一直在烦躁,不如踏踏实实静下来心,抓紧时间提高效率,总能完成的。升华往往就在这些关键时机,要把握住呀,诸位(づ ̄3 ̄)づ╭❤~

一、思路

建树的思路

  • 若已知后缀表达式,建树。算法实现为从左开始向右遍历后缀表达式的元素,新建一个树节点p,值为当前元素的值。如果取到的元素是操作数,直接把p入栈;如果是运算符,从栈中弹出2个节点,把第一个弹出的节点作为p的右子树,第二个弹出的节点作为p的左子树,然后把p入栈。当遍历完逆波兰式时,树的根节点就保存在栈里了。
  • 若已知中缀表达式,建树。使用栈操作,需要将其转化为后缀表达式,再执行建树操作,此处不采用此方法。参考网上代码,采用直接对中缀表达式进行处理的方法。

二、处理过程

  • 和普通二叉树不同,表达式二叉树的结点私有成员变量包含的结点值是字符数组类型。因此在对结点初始化时需注意赋值条件。当查找到某个表达式字符要作为根结点时,才开始初始化结点类。
  • 在完成此次作业过程中,在有个问题的理解上纠结了挺久的。已知算术表达式的中缀或后缀,其算术表达式唯一吗?起初我以为是唯一的(事实上就是唯一的),若已知算术表达式的中缀a+b*c/d,想当然解出其后缀表达式abc*+d/,这样相当于知道了该表达式的中序和后序遍历,然后由中序和后序的遍历结果即可求出唯一的二叉搜索树。然后代入老师给出的题目案例(已知中序和后序遍历的序列及所建的表达式二叉树),也就是代入了中序遍历序列,但ppt上的树和代码跑出的树竟不一样。开始产生疑惑,对比思考后发现,算数表达式是唯一的,只是我想当然把中缀表达式和中序遍历等同化了。
    现总结得出结论:中序遍历的序列不一定是中缀表达式,因为遍历序列不包含符号(),如:不同的中缀表达式a+b*c-d-e/fa+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^)┛

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值