表达式与表达式树

        在网上很难找到解释后缀表达式生成算法和表达式树生成算法的文章,只能自己试着理解一下了。

----------------------------------------------------------------------------------------------------------------------------------------------------

    表达式(expression)指的是一组运算。这里只考虑四则运算和“()”。
    表达式所传达的信息包括(1)一组运算的运算符(operator,操作符),如+* (2)参与这些运算的数(operand,操作数),如1,2 (3)操作符和自己的操作数之间的映射关系。因此,只要能表出上述信息,就可以说是表达式的另一种形式。
    中缀表达式将操作符置于操作数中间,当出现“操作数争议”时(比如1+2*3,2是参与+运算还是参与*运算),使用()和优先级表明操作数的的归属问题。后缀表达式,也称逆波兰式(reverse-Polish expression),将操作符置于操作数之后,即任意操作符之前的连续2个操作数被视为该操作符的操作数。相应的,有前缀表达式。一个中缀、后缀、前缀表达式的例子如下:
    中缀:1+2+(3+4)*5+6+7
    后缀:12+34+5*+6+7+
    前缀:++++12*+34567
    由例子可见,后缀表达式是通过操作符的优先级和括号辅助解决了操作数的争议问题,考虑到这一点,不难发现,操作符的优先级其实只有本地意义:只有相邻的两个操作才会拥有共同的操作数(中间的);而当相距较远的操作符决定运算顺序时,优先级是没有意义的。与优先级相比,真正决定运算顺序的其实是操作符的出现次序。比如,表达式1+2+3*4中,*的优先级比+高,并不意味着*第一个执行,而第一个执行的操作(至少可以是)1+2。再如,在上面的中缀表达式中,虽然()具有最高优先级,但这并不意味着()内的3+4会被第一个执行。()并不意味着“先进行”,只意味着“操作数的强制归属”。比如2+(3+4),意思是3归属于后面的+,同时3+4的结果作为前面+的操作数。故而,一个运算先于前面的运算执行,只是因为前面的运算“需要”后面的运算执行完,以提供一个操作数,进一步,是这种“需求”决定了后面的操作执行的时机。故而,中缀表达式中的运算顺序是1+2,3+4,7*5, 3+35, 35+6, 41+7,与后缀表达式和前缀表达式表表示的运算顺序完全一致。
    在运算顺序方面,中缀表达式是很复杂的——它由3个因素,即操作符出现次序,运算优先级和()共同决定。同样在运算顺序方面,后缀表达式和前缀表达式就简单得多——运算顺序只和操作符出现次序有关,而且考虑到从操作符去寻找其对应的操作数是一件很简单的事情,不难发现利用前缀和中缀表达式求表达式的值更简单,尤其是对于计算机而言。由于栈有“记忆性”——当读到某个操作符时,可以“记起”前面的两个操作数,故而正好被选择用来计算前缀、后缀表达式的值。
    至此,得到了计算表达式的值的一个方法:中缀表达式->(前)后缀表达式->值。
    
    如何将中缀表达式转化成(前)后缀表达式呢?这是个问题。
    由前面的讨论不难看出,这个问题就是“如何将中缀表达式的操作数承接关系梳理出来,然后将操作从前到后排列”,因为那就是后缀表达式中描述运算顺序的方式。因此,我们需要考虑(1)次序(2)括号(3)优先级。这是个复杂的问题。
    解决这个问题的经典方法是利用栈。在该方法中,表达式中的操作符会按照从左到右的顺序依次入栈,而操作数直接作为结果输出,也可以存储为一个队列或者另一个栈。重点在于存储操作符的栈。在压栈时,一些微妙的操作保证了“(1)先执行的操作先出栈,后执行的后出栈 (2)操作符出栈时,它的操作数已经出栈了”。
    a #1 b #2 c #3 d #4 e #5 f
    我们首先考虑没有括号的情况。这时,决定运算顺序的只有(1)次序,即左先右后,(2)优先级。OK!开始!。第一个操作数a输出,然后#1压栈。由于#1的右操作数尚未输出,所以#1不能输出,先存储在栈里面。然后b输出。然后考虑#2。微妙的操作出现了。#2的优先级是否比#1高呢?(情况1)如果是,就意味着#2必须先于#1出栈,从而提供#1的右操作数;(情况2)如果否(包括#1优先级和#2相同,也包括更高),那么#1应该早于#2出栈,而且#1的操作数a和b已经输出了,#1大可出栈先。假设(情况1)成立,那么#2入栈(#2不能直接输出,因为#2的操作数还没出现)。然后c输出。我们对#3做同样的处理,假设#3落入了(情况1),那么#3入栈。现在分析一下栈里的情况,我们发现栈下部的操作符在“等待”上部的操作符——上部的操作符先出栈,意味着在输出的结果中,上部的操作符排列在前侧,从而先执行——这正是我们想看到的。接下来,我们假设#4落入了(情况2),那么#3出栈。这时,输出中已经出现了cd#3,接下来的问题是:cd#3作为一个新的操作数,是归属于#2呢,还是#4。因此,我们继续比较#2和#4的优先级,根据比较结果执行操作。假设(情况2)发生,那么cd#3作为新操作数,归#2所有,这导致#2出栈。这时,输出中出现了新的操作数,那就是bcd#3#2。于是这又成了#1和#4之间的“争议”。比较#4和#1,假设(情况1)发生,即bcd#3#2被#4“抢到”,那么#4入栈。如果接下来#5和#4之间的比较结果落入情况(2),那么输出的结果就会出现 bcd#3#2e#4。这个过程一直持续下去,直到整个表达式被读完。输出即正确的后缀表达式。
    优先级的高低是为了处理操作数的争议问题,而所谓运算顺序的本质就是一系列明确的操作数归属。操作数争议只出现在相邻的操作符之间,因此将待处理操作符和栈顶操作符比较,而根据比较结果作出的不同操作,则对应了操作数的不同归属。很多时候,待处理的操作符和栈顶操作符在中缀表达式中并不相邻,但是上述微妙操作则保证了待处理操作符和栈顶操作符之间一定只隔着已经计算出的中间结果。所以算法实现的过程,就是争议操作数的归属判定过程。
    如果有括号呢?括号意味着子表达式的出现,意味着括号内的操作必须先于栈内已有元素出栈,因而必须首先入栈。对括号内表达式的处理可以看做是对子表达式的处理,'('可以看做和子表达式对应的"子栈"的栈底。因此当读入'('时,按照上述原则依次处理与之成堆的')'之间的表达式即可。当遇到成对的')'时,要弹出这对()之间的所有操作符(类似于读完整个表达式后的操作)。()内的表达式必须计算完,从而保证()前的那个操作可以进行(它在等待操作数)。

    表达式树是表达式的另一种表示方式。表达式树利用节点之间的父子关系表示各个操作间操作符的继承关系。采用一种类似于对后缀表达式求值的方法,可以轻易的将后缀表达式转化成表达式树。对表达式树进行中序、先序和后序遍历,就能方便的得到中缀、前缀、后缀表达式。表达式树也可以通过递归方便的求出表达式的值。

    我用C++演示相关的操作。程序首先将一个ASCII的表达式“符号化”,即搞清楚哪些符号是操作数哪些符号是操作符。Character类就是为这个工作而定义的。Expression类先后将中缀形式的表达式输出,将中缀表达式转化成后缀表达式,计算后缀表达式的值,然后从中缀表达式梳理出表达式树(算法上相当于中缀转后缀算法和后缀表达式值的计算算法的结合,其实从后缀表达式直接转化成表达式树也可),先序、中序、后序遍历表达式树,最后计算出表达式树的值(算法由后序遍历稍作改动可得)。
    注释懒的加了。

#include <stdio.h>
#include <string.h>
#define STACK_SIZE 100
#define EXPRESSION_LENGTH 100
#define OPERATOR_T 1
#define OPERAND_T 2
#define INORDER 1
#define POSTORDER 2
#define PREORDER 3

class character
{
public:
	int value;
	int character_type;
	int level;

    character()
	{
        value = 0;
		character_type = 0;
		level = 0;
	}

    int ASCII2character(char* input) //return length, if input point to "124", return 3
	{
		int length = 0;
		if(((*input) >= 48) && ((*input) <= 57))  //'0' - '9'
		{
            while( ((*input) >= 48) && ((*input) <= 57))
			{
                value = 10 * value + (*input - 48);
			    length++;
				input++;
			}
			character_type = OPERAND_T;
			return length;
		}
        else  //other character
		{
		    value = *input;
            character_type = OPERATOR_T;
			if(((*input) == '+') || ((*input) == '-'))
			{
				level = 1;
			}
			else if(((*input) == '*') || ((*input) == '/')) 
			{
				level = 2; 
			}
			else // '('')'
			{
				level = 3;
			}
            return 1;
		}
	}
    
	void show()
	{
		if(character_type == OPERAND_T)
		{
            printf("%d", value);
		}
		else
		{
            printf("%c", value);
		}
	}
};

class stack
{
public:
	int topPtr;
    character element[STACK_SIZE];

	stack()
	{
		topPtr = -1;
	}

    character* pop()
	{
		if(topPtr < 0)
		{
			return (character*)-1;
		}
		else
		{
		   topPtr--;
           return &(element[topPtr+1]);
		}
	}

    int isFilled()
	{
         return topPtr;
	}

	character* glance()
	{
		if(topPtr < 0)
		{
			return (character*)-1;
		}
		else
		{
           return &(element[topPtr]);
		}
	}

	int push(character* input)
	{
		if(topPtr == (STACK_SIZE-1))
		{
            return -1;
		}
		else
		{
			topPtr++;
			element[topPtr] = *input;
			return 1;
		}
	}
};

class node
{
public:
    node *leftChild;
	node *rightChild;
	character node_value;


	node()
	{
        leftChild = NULL;
		rightChild = NULL;
	}

};

class nodePtrStack
{
public:
	int topPtr;
    node* element[STACK_SIZE];

	nodePtrStack()
	{
		topPtr = -1;
	}

    node* pop()
	{
		if(topPtr < 0)
		{
			return (node*)-1;
		}
		else
		{
		   topPtr--;
           return element[topPtr+1];
		}
	}

    int isFilled()
	{
         return topPtr;
	}

	node* glance()
	{
		if(topPtr < 0)
		{
			return (node*)-1;
		}
		else
		{
           return element[topPtr];
		}
	}

	int push(node* input)
	{
		if(topPtr == (STACK_SIZE-1))
		{
            return -1;
		}
		else
		{
			topPtr++;
			element[topPtr] = input;
			return 1;
		}
	}
};



class expression
{
public:
	character expre_infix[EXPRESSION_LENGTH];
	character expre_postfix[EXPRESSION_LENGTH];
	node *expression_tree;
    int value;

	expression()
	{
        value = 0;
		expre_infix[0].value = '\0';
		expre_postfix[0].value = '\0';
	}

	void get_expression(char *ptr)
	{   
		int i = 0;
		int step;
        while((*ptr) != '\0')
		{
			while(*ptr)
			{
			    step = expre_infix[i].ASCII2character(ptr);
				ptr += step;
				i++;
			}
		}
        expre_infix[i].ASCII2character((ptr));
	}

	void in2post()
	{
        stack operatorStack;
		int i = 0;
		int j = 0;

		while(expre_infix[i].value != '\0')
		{
			//int value;
	        //int character_type;
	        //int level;
            if(expre_infix[i].character_type == OPERAND_T)
			{
                 expre_postfix[j] = expre_infix[i];
				 j++;
				 i++;
			}
			else if(expre_infix[i].character_type == OPERATOR_T)
			{
                 if(expre_infix[i].value == '(')//(
				 {
                       operatorStack.push(&(expre_infix[i]));
				 }
				 else if(expre_infix[i].value == ')')//)
				 {
                       	while(operatorStack.glance()->value != '(') //pop all elements in the stack
						{
                           expre_postfix[j] = *(operatorStack.pop());
			               j++;
						}
                        operatorStack.pop();
				 }
				 else if((operatorStack.isFilled() < 0) || (operatorStack.glance()->value == '(') || (expre_infix[i].level > (operatorStack.glance())->level))
				 {
                       operatorStack.push(&(expre_infix[i]));
				 }
				 else if(expre_infix[i].level <= (operatorStack.glance())->level)
				 {
					   while((operatorStack.isFilled() >= 0) && (operatorStack.glance()->value != '(') && (expre_infix[i].level <= (operatorStack.glance())->level))
                       {
						   expre_postfix[j] = *(operatorStack.pop());
					       j++;
					   }
					   operatorStack.push(&(expre_infix[i]));
				 }
				 else
				 {

				 }
				 i++;
			}
			else
			{

			}
		}//end of while(expre_infix[i].value != '\0')
		while(operatorStack.isFilled() >= 0) //pop all elements in the stack
		{
              expre_postfix[j] = *(operatorStack.pop());
			  j++;
		}
        expre_postfix[j].value = '\0';
	}

	void exprs2tree()
	{
		stack operatorStack;
		nodePtrStack treeStack;
		int i = 0;

		while(expre_infix[i].value != '\0')
		{
			//int value;
	        //int character_type;
	        //int level;
            if(expre_infix[i].character_type == OPERAND_T)
			{
				 node *tempNode = new node;
				 tempNode->node_value = expre_infix[i];
                 treeStack.push(tempNode);
			}
			else if(expre_infix[i].character_type == OPERATOR_T)
			{
                 if(expre_infix[i].value == '(')//(
				 {
                       operatorStack.push(&(expre_infix[i]));
				 }
				 else if(expre_infix[i].value == ')')//)
				 {
                       	while(operatorStack.glance()->value != '(') //pop all elements in the stack
						{  
           				   node *tempNode = new node;
						   tempNode->node_value = *(operatorStack.pop());
						   tempNode->rightChild = treeStack.pop();
						   tempNode->leftChild = treeStack.pop();
                           treeStack.push(tempNode);
						}
                        operatorStack.pop();
				 }
				 else if((operatorStack.isFilled() < 0) || (operatorStack.glance()->value == '(') || (expre_infix[i].level > (operatorStack.glance())->level))
				 {
                       operatorStack.push(&(expre_infix[i]));
				 }
				 else if(expre_infix[i].level <= (operatorStack.glance())->level)
				 {
					   while((operatorStack.isFilled() >= 0) && (operatorStack.glance()->value != '(') && (expre_infix[i].level <= (operatorStack.glance())->level))
                       {
      		   			   node *tempNode = new node;
                           tempNode->node_value = *(operatorStack.pop());
						   tempNode->rightChild = treeStack.pop();
						   tempNode->leftChild = treeStack.pop();
                           treeStack.push(tempNode);
					   }
					   operatorStack.push(&(expre_infix[i]));
				 }
				 else
				 {

				 }
			}
			else
			{

			}
			i++;
		}//end of while(expre_infix[i].value != '\0')
		while(operatorStack.isFilled() >= 0) //pop all elements in the stack
		{
			    node *tempNode = new node;
                tempNode->node_value = *(operatorStack.pop());
			    tempNode->rightChild = treeStack.pop();
				tempNode->leftChild = treeStack.pop();
                treeStack.push(tempNode);
		}
		expression_tree = treeStack.pop();
	}

	int value_postfix()
	{
		character operand1, operand2,result_temp;
		char operation;
		int i=0;
		stack myStack;
		while(expre_postfix[i].value != '\0')
		{
			myStack.push(&(expre_postfix[i]));
			if(myStack.glance()->character_type == OPERATOR_T)
			{
				operation = myStack.pop()->value;
                operand2 = *(myStack.pop());
                operand1 = *(myStack.pop());
				if(operation == '+')
				{
                     result_temp.character_type = OPERAND_T;
                     result_temp.value = operand1.value + operand2.value;
                     myStack.push(&(result_temp));
				}
				else if(operation == '-')
				{
                     result_temp.character_type = OPERAND_T;
                     result_temp.value = operand1.value - operand2.value;
                     myStack.push(&(result_temp));
				}
				else if(operation == '*')
				{
                     result_temp.character_type = OPERAND_T;
                     result_temp.value = operand1.value * operand2.value;
                     myStack.push(&(result_temp));
				}
			}
			i++;
		}
		return myStack.pop()->value;
	}
	int value_tree()
	{
		return value_tree_child(expression_tree);
	}

	int value_tree_child(node *input)
	{
         if (input -> node_value.character_type == OPERAND_T)
		 {
			 return input ->node_value.value;
		 }
		 else // OPERATOR
		 {
             if(input -> node_value.value == '+')
			 {
                    return value_tree_child(input -> leftChild) + value_tree_child(input -> rightChild);
			 }
             else if(input -> node_value.value == '-')
			 {
                    return value_tree_child(input -> leftChild) - value_tree_child(input -> rightChild);
			 }
             else if(input -> node_value.value == '*')
			 {
                    return value_tree_child(input -> leftChild) * value_tree_child(input -> rightChild);
			 }
			 else
			 {
				    return 0;
			 }
		 }
	}

	void show_infix()
	{
		int i = 0;
    	printf("infix: ");
		while(expre_infix[i].value != '\0')
		{
             if((expre_infix[i].character_type == OPERAND_T))
			 {
                 printf("%d", expre_infix[i].value);
			 }
			 else if((expre_infix[i].character_type == OPERATOR_T))
			 {
                 printf("%c", expre_infix[i].value);
			 }
			 else
			 {
				 //nothing
			 }
			 i++;
		}
		printf("\n");
	}
	void show_postfix()
	{
	    int i = 0;
    	printf("postfix: ");
		while(expre_postfix[i].value != '\0')
		{
             if((expre_postfix[i].character_type == OPERAND_T))
			 {
                 printf("%d", expre_postfix[i].value);
			 }
			 else if((expre_postfix[i].character_type == OPERATOR_T))
			 {
                 printf("%c", expre_postfix[i].value);
			 }
			 else
			 {
				 //nothing
			 }
			 i++;
		}
		printf("\n");
	}

	void show_tree(int flag)
	{
		visit(expression_tree, flag);
		printf("\n");
	}

	void visit(node *input, int flag)
	{
	    if(flag == PREORDER)
		{
            input->node_value.show();		
		}

		if(input -> leftChild != NULL)
		{
           visit(input->leftChild, flag);
		}

	    if(flag == INORDER)
		{
        input->node_value.show();		
		}

		if(input -> rightChild != NULL)
		{
		   visit(input->rightChild, flag);
		}

	    if(flag == POSTORDER)
		{
            input->node_value.show();		
		}	
	}
};

void main()
{
	char *expre = "1+2+(3+4)*5+6+7";
	expression myExpression;

	myExpression.get_expression(expre);   //ASCII  -> Character

	myExpression.show_infix();
	printf("\n");
	
	myExpression.in2post();
	myExpression.show_postfix();
	printf("value_postfix_expression: %d\n", myExpression.value_postfix());
	printf("\n");

	printf("expression tree is generated from infix expression....\n");	
	myExpression.exprs2tree();
	printf("inorder traversal of expression tree: ");	
	myExpression.show_tree(INORDER);
	printf("postorder traversal of expression tree: ");
	myExpression.show_tree(POSTORDER);
	printf("preorder traversal of expression tree: ");	
	myExpression.show_tree(PREORDER);
    printf("value_expression_tree: %d\n", myExpression.value_tree());
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值