前中后缀表达式以及表达式树

中缀表达式就是我们平时喜闻乐见的形式:二元运算符在中间,它的两个操作数在两侧:

a + b * c + ( d * e + f ) * g

后缀和前缀表达式,顾名思义就是把运算符分别放在前面或者后面,注意没有括号,手工转换方法是按运算顺序添加括号,然后把相应的运算符置于相应的括号的前或后,如:

((a + ( b * c)) + (((d * e) + f) * g))

放到前面有:

+(+(a*(b c))*(+((*(d e))f)g))

放到后面有:

((a(b c)*)+(((d e)*f)+g)*)+

去掉括号,前缀表示式为:

++a*bc*+*defg

后缀表达式为:

abc*+de*f+g*+

很明显地可以看到他们和中缀表达式的区别在于,他们的优先级信息蕴含在式子里,不需要额外的括号,求值方法是。对于前缀表达式:

从右向左扫描式子,从右边第一个字符开始判断,如果当前字符是数字则一直到数字串的末尾再记录下来,如果是运算符,则将右边离得最近的两个“数字串”作相应的运算,以此作为一个新的“数字串”并记录下来。一直扫描到表达式的最左端时,最后运算的值也就是表达式的值。

对于后缀表达式,原理是一样的,只是读取表达式的方向相反,从左向右扫描表达式。

两种方式都很容易地用栈来实现,因此,计算机通常才用这种方式来计算

表达式树,即把表达式组织成一棵树,以操作符为根节点,操作数为叶子,递归地组织即可。容易知道,对表达式树分别进行前中后遍历即可分别得到前中后缀表达式。

中缀表达式和后缀表达式之间的转换

借助于栈,实现很简单

1、如果遇见右括号,就弹出栈中元素,直到遇到左括号

2、遇到运算符,则与栈顶的当前运算符比较。高于栈顶则入栈,否则出栈,直到栈顶运算符的优先级比它低。对于左括号,直接入栈

3、遇到操作数,则直接写到后缀表达式里。

实现如下:

int infix_to_postfix(char *in, char *post, Stack* st)
{
	int infix_len = strlen(in), i, j;

	for (i = 0, j = 0; i < infix_len; i++)
	{
		if (isdigit(in[i]) || isalpha(in[i])) {
			post[j++] = in[i];
		}
		else if (in[i] == '(') {
			push(&st, in[i]);
		}
		else if (in[i] == ')') {
			while (check_top(st) != '(')
			{
				post[j++] = pop(&st);
			}
			pop(&st);
		}
		else {
			//pop if the operator's priority is less or equal than the top
			while (!isempty_stack(st) && check_top(st) != '(' && get_priority(in[i]) <= get_priority(check_top(st)))
			{
				post[j++] = pop(&st);
			}
			push(&st, in[i]);
		}
	}
	while (!isempty_stack(st))
	{
		post[j++] = pop(&st);
	}
}

中缀和前缀表达式的转换

基本类似与中缀与后缀,只不过是倒序读入。并在结束后,倒序输出:

1、如果遇见左括号,就弹出栈中元素,直到遇到右括号

2、遇到运算符,则与栈顶的当前运算符比较。高于栈顶则入栈,否则出栈,直到栈顶运算符的优先级不比它低(包括相等)。对于右括号,直接入栈

3、遇到操作数,则直接写到前缀表达式里。

实现如下:

int infix_to_prefix(char *in, char *pre, Stack* st)
{
	reverse_str(in);
	int infix_len = strlen(in), i, j;

	for (i = 0, j = 0; i < infix_len; i++)
	{
		if (isdigit(in[i]) || isalpha(in[i])) {
			pre[j++] = in[i];
		}
		else if (in[i] == ')') {
			push(&st, in[i]);
		}
		else if (in[i] == '(') {
			while (check_top(st) != ')')
			{
				pre[j++] = pop(&st);
			}
			pop(&st);
		}
		else {
			//pop if the operator's priority is less than the top
			while (!isempty_stack(st) && check_top(st) != ')' && get_priority(in[i]) < get_priority(check_top(st)))
			{
				pre[j++] = pop(&st);
			}
			push(&st, in[i]);
		}
	}
	while (!isempty_stack(st))
	{
		pre[j++] = pop(&st);
	}
	reverse_str(pre);
}

通过后缀表达式生成表达式树的方式和计算后缀表达式类似:从左向右扫描,读到操作数则生成叶子节点,读到每个操作符,出栈两个,同时操作符作父节点,组合成一个树,然后父节点进栈,依次类推,实现如下:

Bintree_node* postfix_to_tree (char *s, Stack* st)
{
	char *p;
	int len = strlen(s), i;
	Bintree_node * p_node, *op1, *op2;

	for (p = s, i = 0; i < len; i++)
	{
	//	while (*(p+i) == ' ') i++;

		if (isdigit(*(p+i))) {
			p_node = (Bintree_node*)malloc(sizeof(Bintree_node));
			p_node -> ele = *(p+i);
			p_node -> left = NULL;
			p_node -> right = NULL;
			push(&st, p_node);
		}
		else if (*(p+i) == '+' || *(p+i) == '*' || *(p+i) == '/' || *(p+i) == '-') {
			op1 = pop(&st);
			op2 = pop(&st);

			p_node = (Bintree_node*)malloc(sizeof(Bintree_node));
			p_node -> ele = *(p+i);
			p_node -> left = op2;
			p_node -> right = op1;
			push(&st, p_node);
		}
	}
	return pop(&st);
}

前中后缀表达式以及表达式树,布布扣,bubuko.com

时间: 2024-08-02 10:58:40

前中后缀表达式以及表达式树的相关文章

C#中的Lambda表达式和表达式树

在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在不牺牲可读性的前提下,进一步简化了委托. LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态.这些操作表示了各种关于数据的逻辑,例如数据筛选,数据排序等等.通常这些操作都是用委托来表示.Lambda表达式是对LINQ数据操作的一种符合语言习惯的表示方式. Lambda表达式不仅可以用来创

16.C#初见Lambda表达式及表达式树(九章9.1-9.3)

在说明Lambda相关知识前,我们需要了解Lambda表达式常用于LINQ,那么我们来聊下LINQ. LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态.这些操作表示了各种关于数据的逻辑:如何过滤.如何排序以及如何将不同的数据源连接在一起,等等.执行委托只是LINQ的众多能力之一.为了富有效率地使用数据库和其他查询引擎,我们需要以一种不同的方式来表示管道中的各个操作.这种不同的方式就可以使用Lambda表达式来表现.下面分别使用委托(使用匿名函数)和Lambda表达式来作出同样的事情

[.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用

[.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用 本节导读:讨论了表达式树的定义和解析之后,我们知道了表达式树就是并非可执行代码,而是将表达式对象化后的数据结构.是时候来引用他解决问题.而本节主要目的就是使用表达式树解决实际问题. 读前必备: 本节学习前,需要掌握以下知识: A.继承 [.net 面向对象编程基础]  (12) 面向对象三大特性——继承 B.多态 [.net 面向对象编程基础]  (13) 面向对象三大特性——多态 C.抽象类 [.net 面向

[.net 面向对象程序设计进阶] (5) Lamda表达式(二) 表达式树快速入门

[.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门 本节导读: 认识表达式树(Expression Tree),学习使用Lambda创建表达式树,解析表达式树. 学习表达式在程序设计中的优点:比如构造动态查询.动态构造表达式树完成未知对象属性访问,比反射的性能高出很多.我们可以说表达式树才是Lambda的精髓,是我们必须要熟练掌握并灵活运用的. 1.关于表达式树(Expression Tree) 表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如

Lambda表达式和表达式树

在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在不牺牲可读性的前提下,进一步简化了委托. LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态.这些操作表示了各种关于数据的逻辑,例如数据筛选,数据排序等等.通常这些操作都是用委托来表示.Lambda表达式是对LINQ数据操作的一种符合语言习惯的表示方式. Lambda表达式不仅可以用来创

数据结构中缀表达式转后缀表达式以及后缀转中缀表达式

最近一直在看数据结构这本书,我相信,对于每个程序员来说,数据结构都尤为重要.为什么要学,可以看看这位博友的认识http://blog.csdn.NET/sdkfjksf/article/details/54380659 直入主题:将中缀表达式转为后缀表达式 以及将后缀表达式转为前缀表达式的实现. 关于后缀转中缀,中缀转后缀的理论介绍,请先阅读其互转的理论知识,或者我转发的这篇文章,这里不再累赘,最好参考<数据结构与算法描述Java语言版>,接下来将会用java写. 一.首先,怎么实现中缀表达式

ACM:树的变换,根据表达式建立表达式树

题目:输入一个表达式,建立一个表达式树! 分析:找到最后计算的运算符(它是整棵表达式树的根),然后递归处理! 在代码中,只有当p==0的时候,才考虑这个运算符,因为括号里的运算符一定不是最后计算的,应当忽略! 由于加减跟乘除都是左结合的,最后一个运算符才是最后计算的,所以用两个变量c1跟c2分别记录在括号外面的"最右"出现的加减号和乘除号. #include <iostream> #include <string> using namespace std; co

C#复习笔记(4)--C#3:革新写代码的方式(Lambda表达式和表达式树)

Lambda表达式和表达式树 先放一张委托转换的进化图 看一看到lambda简化了委托的使用. lambda可以隐式的转换成委托或者表达式树.转换成委托的话如下面的代码: Func<string, int> getLength = s => s.Length; 转换成表达式树的话是下面的代码: Expression<Func<string, int>> getLength = s => s.Length; 委托方面的东西前面都做了详细的介绍.我们主要学习表达

c#中匿名函数lamb表达式

c#中匿名函数lamb表达式 实例一:(其实,这样都是些语法糖) using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication2 { //c#中的匿名函数 //申明一委托 delegate void Del(); class Program { static void s