• 表达式树


    【0】README

    0.1)本文旨在总结出表达式树的构建步骤, 其中还涉及到中缀转后缀表达式,以及如何计算 表达式树中的值;
    0.2)本文源代码均为原创;
    0.3) 其实, 实现一个简单的计算器, 也即求出中缀表达式的值,我们也可以用栈来实现, 参见 http://blog.csdn.net/pacosonswjtu/article/details/49225529 ; 此处给出 表达式树的实现 仅在于加深对表达式树的理解及它的应用;


    ##**【1】表达式树 的相关概念** **1.1)定义:**表达式树的树叶是 操作数operand,比如常量或变量,而其他节点是操作符 operator; ![这里写图片描述](http://img.blog.csdn.net/20151021201547456) **1.2)对上图中的表达式进行遍历(先序+中序+后序)**
    • 先序遍历: + + a * b c * + * d e f g
    • 中序遍历: a + b * c + ( d * c + f ) * g (这里要加上括号, 这也是我们为什么要采用 后缀或逆波兰记法 来表示 用户输入的运算表达式 以计算结果, 一句话,方便可靠)
    • 后序遍历: a b c * + d e * f + g * +
    • Attention)这里,我们没有给出源代码,因为这个先序,后序 or 中序 的源代码和二叉树遍历的源代码相差无几,这里只是了解下 表达式树的概念,并了解下用 树的遍历计算 表达式的值;

    【2】如何构造一颗表达式树(表达式树的定义很关键,对于写我们的递归程序而言)

    我们给出一种算法将后缀表达式转变为 表达式树:

    • step1)用户输入中缀表达式, 我们首先将其转为后缀表达式;
    • step2)我们将后缀表达式转为 表达式树的形式;
    • step3)我们来计算该表达式树的计算结果是多少?

    **2.1 ) download source code: ** https://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter4/p71_compute_expr_tree

    这里写图片描述
    **2.2 ) source code at a glance: **

    2.2.1)expr_tree.c source code :

    #include "stack.h"
    #include "binary_tree.h"
     
    extern void infir_to_postfix();
    extern int computeResult(int operand1, int operand2, int operator_);
    extern ElementType compute_postfix();
    extern Stack operand;
    extern int isOperator(char ch);
    extern int computeResult(int operand1, int operand2, int operator_);
    
    // building an expr tree for storing postfix expr
    BinaryTree postfixToExprTree()
    {			
    	int value;		
    	BinaryTree* treeArray;	
    	int size;
    	int index;
    	ElementType *p;
    	int i ;
    
    	size = getTopOfStack(operand) + 1; //get the top of stack, and add 1 to compute size of the stack
    	treeArray = (BinaryTree*)malloc(size * sizeof(BinaryTree)); // alloc memory for treeArray
    	index = 0; // set the index of treeArray 0 
    	
    	p = getArray(operand);
    	i = 0;
    	while(i < getTopOfStack(operand))
    	{
    		value = *(p+i++);
    		if(value == ' ') // if the value equals ' ', continue 
    			continue;
    		treeArray[index++] = createBinaryTree(value);// for every element need to build tree node
    		if(isOperator(value)) // if the value belongs to operator, 
    		{	
    			index--;						
    			insertNode(treeArray[index-1], treeArray[index], 0);			
    			insertNode(treeArray[index-2], treeArray[index], 1);
    			treeArray[index-2] = treeArray[index];
    			index --;
    		}		
    		// (treeArray+index++) = createBinaryTree(value);// if the value belongs to operand, push the element into the treeArray
    	}
    	return *treeArray;
    }
    
    // preorder the tree
    void printPreorder(int depth, BinaryTree root)
    {			
    	int i;
    		
    	if(root) {		
    		for(i = 0; i < depth; i++)
    			printf("    ");		
    		printf("%c
    ", root->value);
    		printPreorder(depth + 1, root->left);											
    		printPreorder(depth + 1, root->right); // Attention: there's difference between traversing binary tree and common tree							
    	}
    	else {
    		for(i = 0; i < depth; i++)
    			printf("    ");		
    		printf("NULL
    ");
    	}
    }
     
    // postordering expression tree with operantors and operands to compute the result of these nodes
    int postorder_compute_postfix_expr_tree(BinaryTree root)
    {	
    	int temp1;
    	int temp2;
    
    	if(isOperator(root->value)) {						
    		temp1 = postorder_compute_postfix_expr_tree(root->left);											
    		temp2 = postorder_compute_postfix_expr_tree(root->right); // Attention: there's difference between traversing binary tree and common tree										
    		return computeResult(temp1, temp2, root->value);
    	}
    	else  
    		return root->value - 48;	 
    }
     
    
    int main()
    {		
    	BinaryTree bt;
    
    	// 1.convert infix into postfix expr
    	printf("
     ====== convert infix into postfix expr ====== 
    ");
    	infir_to_postfix();	// after this func is called over, we get the postfix of the expr
    		
    	// 2.convert postfix into the expression tree	
    	bt = postfixToExprTree();
    	printPreorder(1, bt); 
    
    	//3.compute postfix expr stored in the expression tree
    	printf("the final result is : %2d 
    ", postorder_compute_postfix_expr_tree(bt));
    
    	return 0;
    }
    

    2.2.2)binary_tree.c source code :

    #include "binary_tree.h"
    
    // create a BinaryTree with root node
    BinaryTree createBinaryTree(TreeElementType value)
    {	
    	BinaryTree t;
    
    	t = (BinaryTree)malloc(sizeof(struct BinaryTree));
        if(!t) {
            Error("out of space, from func createBinaryTree");        
            return NULL;
        }    
    	t->left = NULL;
    	t->right = NULL;	
    	t->value = value;
    	
    	return t;
    }
    
    // make the BinaryTree empty 
    BinaryTree makeTreeEmpty(BinaryTree t)
    {
    	if(t){
    		makeTreeEmpty(t->left);
    		makeTreeEmpty(t->right);		
    		free(t);
    	}			
    	return NULL;
    }
    
    //insert a Tree node with value e into left child or right child of the parent
    BinaryTree insert(TreeElementType e, BinaryTree parent, int isLeft)
    {	
    	BinaryTree node;
    	
    	if(!parent){
    		Error("for parent BinaryTree node is empty , you cannot insert one into the parent node, from func insert");        
            return NULL;
    	}
    
    	node = (BinaryTree)malloc(sizeof(struct BinaryTree));
    	if(!node) {
            Error("out of space, from func insert");        
            return NULL;
        }
    	node->value = e;
    	node->right = NULL;
    	node->left = NULL;// building the node with value e over
    
    	if(isLeft) { // the tree node inserting into left child of the parent 
    		if(parent->left) {
    			Error("for parent has already had a left child , you cannot insert one into the left child, from func insert");        
    			return NULL;	
    		}
    		parent->left = node;
    	}
    	else { // the tree node inserting into right child of the parent 
    		if(parent->right) {
    			Error("for parent has already had a right child , you cannot insert one into the right child, from func insert");        
    			return NULL;	
    		}
    		parent->right = node;
    	}	 
    	return node;	
    }
    
    //insert a Tree node into left child or right child of the parent
    BinaryTree insertNode(BinaryTree node, BinaryTree parent, int isLeft)
    {			
    	if(!parent){
    		Error("for parent BinaryTree node is empty , you cannot insert one into the parent node, from func insert");        
            return NULL;
    	}
    	
    	if(!node) {
            Error("for the node inserted is NULL , so you cannot insert a NULL node, from func insert");        
            return NULL;
        }	 
    
    	if(isLeft)  // the tree node inserting into left child of the parent 		
    		parent->left = node;	 
    	else  // the tree node inserting into right child of the parent 		
    		parent->right = node;		 
    
    	return node;	
    }
    
    // find the BinaryTree root node with value equaling to e
    BinaryTree find(TreeElementType e, BinaryTree root)
    {
    	BinaryTree temp;
    
    	if(root == NULL)
    		return NULL;
    	if(root->value == e)
    		return root;
    
    	temp = find(e, root->left);	
    	if(temp) 
    		return temp;
    	else
    		return 	find(e, root->right);				
    }
    
    // analog print directories and files name in the BinaryTree, which involves postorder traversal. 
    void printPostorder(int depth, BinaryTree root)
    {			
    	int i;
    		
    	if(root) {						
    		printPostorder(depth + 1, root->left);											
    		printPostorder(depth + 1, root->right); // Attention: there's difference between traversing binary tree and common tree
    		for(i = 0; i < depth; i++)
    			printf("    ");		
    		printf("%c
    ", root->value);					
    	}
    	else {
    		for(i = 0; i < depth; i++)
    			printf("    ");		
    		printf("NULL
    ");
    	}
    }
    

    2.2.3)stack.h source code :

    #include <stdio.h>
    #include <malloc.h>
    
    #define ElementType int
    #define EmptyStack -1
    #define Error(str) printf("%s",str) 
    #define FatalError(str) printf("%s",str) 
    #define minStackSize 5
    
    struct Stack;
    typedef struct Stack *Stack;
    
    int isFull(Stack s);
    int isEmpty(Stack s);
    Stack createStack(int);
    void disposeStack(Stack s);
    void makeEmpty(Stack s);
    void push(ElementType e, Stack s);
    ElementType top(Stack s);
    void pop(Stack s);
    ElementType top(Stack s);
    int getTopOfStack(Stack s);
    ElementType *getArray(Stack s);
    
    void printStack(Stack s); 
    void printStack_postfix(Stack s);
    
    struct Stack {
    	int capacity;
    	int topOfStack;
    	ElementType *array;
    } ;
    

    2.2.4)binary_tree.h source code :

    #include <stdio.h>
    #include <malloc.h>
    
    #define TreeElementType char
    #define Error(str) printf("%s",str) 
    
    struct BinaryTree;
    typedef struct BinaryTree *BinaryTree;
    
    BinaryTree createBinaryTree(TreeElementType); // this func is different from that in p70_preorder_binary_tree.c
    BinaryTree makeTreeEmpty(BinaryTree);
    BinaryTree insert(TreeElementType, BinaryTree, int);
    BinaryTree insertNode(BinaryTree, BinaryTree, int);
    BinaryTree find(TreeElementType, BinaryTree);
    void printPostorder(int depth, BinaryTree root);
    
    // we adopt child-sibling notation
    struct BinaryTree
    {
    	TreeElementType value;
    	BinaryTree left;
    	BinaryTree right;
    };
    

    2.2.5)stack.c source code :

    #include "stack.h"
    
    int getTopOfStack(Stack s)
    {
    	return s->topOfStack;
    }
    
    //return stack's array
    ElementType *getArray(Stack s)
    {
    	return s->array;
    }
    
    //judge whether the stack is empty or not
    int isFull(Stack s)
    {
    	return s->capacity - 1 == s->topOfStack ? 1 : 0;	
    }
    
    //judge whether the stack is empty or not
    int isEmpty(Stack s)
    {
    	return s->topOfStack == -1;
    }
    
    //create stack with the head node 
    Stack createStack(int size)
    {
    	Stack s;
    	
    	s = (Stack)malloc(sizeof(struct Stack));
    
    	if(size < minStackSize) {
    		Error("stack size is too small, and creating stack with defualt size 5");	
    		size = minStackSize;
    	}
    	if(s == NULL) {
    		FatalError("out of space when allocting memory for stack s");
    		return NULL;
    	}
    
    	s->array = (ElementType *)malloc(size * sizeof(ElementType));	
    	if(s->array == NULL) {
    		FatalError("out of space when allocting memory for stack's array ");
    		return NULL;
    	}
    	s->topOfStack = -1;
    	s->capacity = size;	
    	return s;
    }
    
    //dispose stack 
    void disposeStack(Stack s)
    {
    	free(s->array);
    	free(s);
    }
    
    //pop all elements in the stack
    void makeEmpty(Stack s)
    {
    	if(s->topOfStack == -1)
    		Error("must create the stack first");
    	while(!isEmpty(s))
    		pop(s);
    }
    
    //push the node with value e into the stack s 
    //attend that first moving ptr ,then executing push operation
    void push(ElementType e, Stack s)
    {
    	ElementType *temp = s->array;
    	
    	if(isFull(s))
    		Error("the Stack is full, push failure! ");			
    	else{
    		s->topOfStack ++;
    		s->array[s->topOfStack] = e;				
    	}		
    }
    
    // pop the node or element on the top of stack 
    //attend that first executing pop operation,then moving ptr
    void pop(Stack s)
    {
    		
    	if(isEmpty(s))
    		Error("empty stack");
    	else 
    		s->topOfStack --;							 
    }
    
    // return the value of the top node in the stack
    ElementType top(Stack s)
    {
    	if(!isEmpty(s))		
    		return s->array[s->topOfStack];
    	Error("the stack is empty from func top
    ");
    	return -1;
    }
    
    //print value of element in the stack s
    void printStack(Stack s)
    {
        int i;
    
        if(isEmpty(s)){
    		Error("empty stack");
    		return ;
        }
    	
    	for(i=0; i<= s->topOfStack; i++) 
    		printf("%4d", s->array[i]);
    	    
        printf("
    ");
    }
    
    //print value of element in the stack s with postfix
    void printStack_postfix(Stack s)
    {
        int i;
    
        if(isEmpty(s)){
    		Error("empty stack");
    		return ;
        }
    	printf("stack elements list: ");
    	for(i=0; i<= s->topOfStack; i++)  	
    		printf("%c", s->array[i]);
    	
        printf("
    ");
    }
    

    2.2.6)compute_postfix.c source code :

    #include "stack.h"
    
    #define Size 100
    
    // refer to p50.c and put it into the same project
    extern struct Stack;
    typedef struct Stack *Stack;
    
    extern Stack operand; // operand is an extern variable defined in infixToPostfix 
    extern int isOperator(char ch);
    extern void infir_to_postfix();
    int computeResult(int operand1, int operand2, int operator_);
    
    int computeResult(int operand1, int operand2, int operator_)
    {
    	switch(operator_)
    	{
    	case '+': return operand1 + operand2;
    	case '*': return operand1 * operand2;
    	default: return 0; break;
    	}
    }
    
    // compute final result of responding postfix 
    ElementType compute_postfix()
    {
    	Stack output;
    	int i;
    	ElementType *p;
    	int value;
    	int operand1;
    	int operand2;
    	 
    	output = createStack(Size); // create stack with length Size
    	i = 0;
    	p = getArray(operand); // get operand->array
    
    	while(i < getTopOfStack(operand))
    	{
    		value = *(p+i++);
    		if(value == ' ')
    			continue;
    		if(isOperator(value))
    		{
    			operand1 = top(output);
    			pop(output);
    
    			operand2 = top(output);
    			pop(output);
    
    			value = computeResult(operand1, operand2, value);
    			push(value, output);
    			continue;
    		}
    		push(value - 48, output);
    	}
    	return getArray(output)[0];
    }
    

    2.2.7)infixToPostfix.c source code :

    #include "stack.h"
    
    #define Size 100
    
    // refer to p50.c and put it into the same project
    extern struct Stack;
    typedef struct Stack *Stack;
    Stack operand; // declaration of Stack operand 
    int isOperator(char ch);
    void infir_to_postfix();
    
    //compare operator's priority between ch1 and ch2, return -1, 0 or 1 
    int priorityBigger(char ch1, char ch2)
    {
    	int size = 8;
    	char operator_[]={ '(', ')', ' ', '+', '-', ' ', '*', '/'};
    	int index1, index2;
    	int i;
    
    	if(ch1 - ch2 == 0)
    		return 0;
    
    	for(i = 0; i< size; i++)
    		if(operator_[i] == ch1)
    		 	index1 = i;			 
    		else if(operator_[i] == ch2)
    		 	index2 = i;					 
    	
    	index1 -= index2;
    
    	if(index1 == 1 || index1 == -1) 
    		return 0;
    	else if(index1 > 1)
    		return 1;
    	else if(index1 < -1)
    		return -1;	
    }
    
    
    //judge whether the ch is operator or not ,also 1 or 0
    int isOperator(char ch)
    {
    	int size;
    	char operator_[]={'(', '+', '-', '*', '/', ')'};
    	int i;
    
    	size = 6;
    	for(i = 0; i < size; i++)
    		if(ch == operator_[i])
    			break;
    
    	return i == size ? 0 : 1;
    }
    
    //convert a part of str with length len into responding element value 
    ElementType strToElement(int *str, int len)
    {
    	int i;
    	int value;
    
    	i = value = 0;
    	while(i < len)
    	{
    		value += *(str+i) - 48;
    		if(++i == len)
    			break;
    		value *= 10;
    	}
    	return value;
    }
    
    // convert infix expr into postfix expr
    //for operand and operator cannot be in the same type ,we treat them as char and split them with space
    void infixToPostfix(Stack s1, Stack s2,char *expr)
    {
    	char ch;	
    	int i;
    	char top_t;	
    	int flag;		
    
    	i = 0;	
    	flag = 0;	 
    	while((ch = *(expr+i++)) != '') 
    	{				
    		if(ch == ')'){// if ch equals ')', pop elements in stack s2 between '(' and ')' into stack s1
    			while((top_t = top(s2)) != '(' ) 
    			{			
    				push(top_t, s1);
    				push(' ', s1);
    				pop(s2);
    			}			
    			pop(s2); // pop '(' in stack s2 			
    			continue;
    		}
    
    		if(isOperator(ch)) // isOperator is true					
    		{ 
    			if(ch == '(') 
    			{
    				push(ch, s2); // push '(' into operator stack s2
    				flag = 1;
    				continue;
    			}			
    
    			while((top_t = top(s2)) != -1 && priorityBigger(top_t, ch) >= 0 && flag ==0) 
    			{							
    				pop(s2);				 
    				push(top_t, s1);
    				push(' ', s1);	
    			}												 
    			push(ch, s2); // push operator into operator stack s2 		 
    			flag = 0;
    		}
    		else 
    		{
    			push(ch, s1);					 
    			push(' ', s1);    // we treat them as char and split them with space
    		}
    			
    	}
    	// pop element in s2 and push it into s1
    	while(!isEmpty(s2)) 
    	{		
    		push(top(s2), s1);
    		push(' ', s1);
    		pop(s2);
    	}	
    }
    
    // read expr from console till '
    ' and we just only focus on '+' and '*';
    // postfix expression like 6 5 2 3 + 8 * + 3 + *
    char *read()
    {
    	char *temp;
    	int len;		
    	char ch;
    			
    	temp = (char*)malloc(Size * sizeof(char));
    	len = 0;			
    	while((ch = getchar()) != '
    ') 
    	{	
    		if(ch == ' ')
    			continue;
    		temp[len++] = ch;	 
    	}
    		
    	temp[len] = '';
    	
    	return temp;
    }  
    
    // there are 2 stacks, that's operand and operator;
    //works list
    //1.read expr, 2.convert the expr from infix to postfix, 3.
    
    /*
    int main()
    {	
    	Stack operand;
    	Stack operator_;
    	operand = createStack(Size);
    	operator_ = createStack(Size);
    	
    	// convert infix into postfix expr
    	infixToPostfix(operand, operator_, read());	
    	printStack_postfix(operand);
    	
    	// compute postfix expr
    	
    	return 0;
    }
    */
    
    void infir_to_postfix()
    {	
    	Stack operator_;
    
    	//create stack operand and operator_
    	operand = createStack(Size);
    	operator_ = createStack(Size);
    	
    	// convert infix into postfix expr
    	infixToPostfix(operand, operator_, read());	
    	printStack_postfix(operand);	
    }
    
  • 相关阅读:
    AndroidStudio中AlertDialog的四种用法(转载)
    ZPL指令封装
    Android程序闪退时写日志并上传到服务器
    sql server 导出表结构
    Kestrel服务器ASP.NetCore 3.1程序启用SSL
    Asp.Net Core 下 Newtonsoft.Json 转换字符串 null 替换成string.Empty(转)
    ApiResult-WebAPI开发统一返回值对象的演化(.net core版)
    EF Core 拓展SqlQuery方法(转载)
    钉钉小程序post提交json,报400、415
    体验.net core 3.1 socket
  • 原文地址:https://www.cnblogs.com/pacoson/p/4903914.html
Copyright © 2020-2023  润新知