表达式树

【0】README

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


【1】表达式树的相关概念

1.1)定义:表达式树的树叶是 操作数operand,比如常量或变量,而其他节点是操作符 operator;
这里写图片描述
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 stacktreeArray = (BinaryTree*)malloc(size * sizeof(BinaryTree)); // alloc memory for treeArrayindex = 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 nodeif(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\n", 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\n");}
}// 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 exprprintf("\n ====== convert infix into postfix expr ====== \n");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 treeprintf("the final result is : %2d \n", 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 overif(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;elsereturn  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 treefor(i = 0; i < depth; i++)printf("    ");     printf("%c\n", root->value);                    }else {for(i = 0; i < depth; i++)printf("    ");     printf("NULL\n");}
}

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 5struct 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\n");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("\n");
}//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("\n");
}

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 Sizei = 0;p = getArray(operand); // get operand->arraywhile(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++)) != '\0') {               if(ch == ')'){// if ch equals ')', pop elements in stack s2 between '(' and ')' into stack s1while((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 s2flag = 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 s1while(!isEmpty(s2)) {       push(top(s2), s1);push(' ', s1);pop(s2);}   
}// read expr from console till '\n' 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()) != '\n') {   if(ch == ' ')continue;temp[len++] = ch;    }temp[len] = '\0';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 exprinfixToPostfix(operand, operator_, read()); printStack_postfix(operand);// compute postfix exprreturn 0;
}
*/void infir_to_postfix()
{   Stack operator_;//create stack operand and operator_operand = createStack(Size);operator_ = createStack(Size);// convert infix into postfix exprinfixToPostfix(operand, operator_, read()); printStack_postfix(operand);    
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/332024.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Date/Timestamp/String/LocalDate/LocalDateTime

文章目录String 转成 DateDate 转成 StringString 转成 Timestamp获取系统当前的毫秒数获取系统当前的日期时间毫秒数转成 Timestamp毫秒数转成 DateTimestamp 转成 StringDate 转成 TimestampTimestamp 转成 Datejava.util.Date 转成 java.sql.Date将带T的日期时间转成正常的日…

python可以用来写什么工具_python写工具

谷歌开源 Python Fire&#xff1a;可自动生成命令行接口今天我们很高兴地宣布 Python Fire 开源。Python Fire 可从任何 Python 代码生成命令行接口(command line interfaces (CLIs))&#xff0c;简单地调用任意 Python 程序中的 Fire 函数以将那个程序自动地转化为 CLI。该库可…

java原始类型和引用类型_Java中的8种原始类型

java原始类型和引用类型几年前&#xff0c;当我开始编辑Java Basics系列时&#xff0c;我认为将一些非常详细的信息拉到自己的帖子中是很有意义的。 这样&#xff0c;初学者的内容就更容易消化了。 首先&#xff0c;我将介绍有关Java的8种原始类型的所有信息。 Java基本类型 正…

androidtabhost缓存_FragmentTabHost布局的使用及优化方式

欢迎Follow我的GitHub, 关注我的简书. 其余参考Android目录.TabHostAndroidFragmentTabHost作为Android4.0版本的控件, 已经被项目广泛使用, 5.0版本又推出TabLayoutViewPager显示多页. 我来讲解如何使用FragmentTabHost.本文源码的GitHub下载地址主要包括:(1) 自定义Tab的图片…

二叉查找树

【0】README 0.1&#xff09;本文的重点在于介绍 二叉查找树的概念&#xff0c;以及写出 二叉查找树的操作例程的源代码&#xff0c; 其中当属delete 操作的源代码最不容易实现&#xff1b; 0.2&#xff09;本文源代码均为原创&#xff0c; 当然 代码中的idea 是借鉴人家的&a…

常用的命名规范/命名规则

文章目录骆驼式命名法&#xff08;CamelCase&#xff09;帕斯卡命名法&#xff08;PascalCase&#xff09;串式命名法&#xff08;KebabCase&#xff09;下划线命名法&#xff08;UnderScoreCase&#xff09;骆驼式命名法&#xff08;CamelCase&#xff09; 也叫小驼峰式命名法…

spring order_Spring @Order批注

spring order介绍&#xff1a; Spring Order注释是在Spring 2.0中首次引入的。 然后&#xff0c;它仅用于定义AspectJ建议中的顺序。 在Spring 4.0的后面&#xff0c;对该注释的实现进行了进一步改进。 从那时起&#xff0c;它还支持对Java数组或List之类的集合中的Spring组件或…

AVL树

【0】README 0.1&#xff09;本文给出了平衡二叉树&#xff08;AVL树&#xff09;的插入例程涉及到的单旋转双旋转的概念&#xff0c;并给出了代码实现&#xff1b; 0.2&#xff09;本文源代码均为原创&#xff0c; 当然相关idea 还是借鉴人家的&#xff1b;&#xff08;真心…

spring 注释_Spring@懒惰注释

spring 注释介绍&#xff1a; 默认情况下&#xff0c; Spring框架在应用程序启动时加载并热切初始化所有bean。 在我们的应用程序中&#xff0c;我们可能有一些非常消耗资源的bean。 我们宁愿根据需要加载此类bean。 我们可以使用Spring Lazy批注实现此目的 。 在本教程中&…

管理系统的账户设计(涉及注册/登录逻辑)

文章目录方案一方案二方案三方案一 类似华为云IAM&#xff08;Identity and Access Management 身份和访问管理&#xff09;用户&#xff0c;阿里云的 RAM&#xff08;Resource Access Management 资源访问管理&#xff09;用户 机构有独立的账户&#xff08;主账户&#xff…

opencv生成日志_OpenCV-Utils学习日志:VideoCapture使用样例

1.VideoCapture可以打开多种来源的数据流&#xff0c;但常见的是相机、视频及图像序列三类数据流&#xff1a;(1)打开相机数据流&#xff0c;需要指定相机在主机上的设备编号&#xff0c;若主机上只有一个相机则编号通常是0。(2)打开视频数据流&#xff0c;需要指定视频的完整路…

jdbc查询序列_JDBC –模拟序列

jdbc查询序列也许我们每个人在程序员的生活中至少遇到过一次这个问题- 如何模拟数据库序列&#xff1f; 在下面&#xff0c;您可能会发现我对该问题解决方案的各种了解。 假设我们有一个接口定义了所需的API&#xff0c;用于返回整数序列&#xff1a; public interface Sequen…

利用 GregorianCalendar 制作当前月的月历

【0】README 0.1&#xff09;本文文字总结于 core java volume 1 &#xff0c; 源代码均为原创&#xff1b; 0.2&#xff09;本文旨在熟悉 GregorianCalendar 日历类&#xff0c;每一天就是一个GregorianCalendar 日历类&#xff0c;一天有很多的日历属性&#xff0c;觉得用它…

pyecharts怎么绘制散点图_PyeCharts绘制各种图形

简介PyeCharts 是一个用于生成 Echarts 图表的类库&#xff0c;用其生成的图可视化效果非常棒&#xff0c;而且使用起来非常简单。下面是一些常用图的pyecharts实现方法柱状图bar pye.Bar("柱状图")#新建柱状图bar.add("服装", #图例名称["衬衫"…

junit junit_穿越JUnit流

junit junit关于JUnit 5迁移的好处之一是&#xff0c;您可以在老式模式下运行JUnit 4测试&#xff0c;并且所有内容仍然兼容。 不利的一面是&#xff0c;某些注释和方法在JUnit 4和JUnit 5中具有相同的名称&#xff0c;并且当两组库依赖项都可用时&#xff0c;很容易导入错误的…

被遗忘的软件产品形态

从2010年以后&#xff0c;很多公司开发的软件产品&#xff0c;很少有客户端了&#xff0c;web2.0之后&#xff0c;主流的业务系统基本上都是基于Web去构建业务系统。这几年见到的业务应用系统都是基于Web的构建的。而在To C市场&#xff0c;几乎就没有客户端了&#xff0c;都是…

vue进行判断使用class_vue判断dom的class

vue点击给dom添加class然后获取含有class的dom{{item.name}}{{item2.name}}jschek(index2, index) {this.iac[index2] indexthis.iac this.iac.concat([]);this.checkchose()},checkchose:function(){var chosethisvar chosedomchose.$refs.choseboxconsole.log(chosedom)for…

方法参数的值调用+引用调用+深浅拷贝

【0】README 0.1&#xff09;本文描述源代码均 转自 core java volume 1&#xff0c; 旨在理清值调用引用调用&#xff1b; 【1】参数传递给方法的专业术语&#xff1a; 1.1&#xff09;值调用&#xff1a;它表示方法接收的是调用者提供的值&#xff1b; 1.2&#xff09;引用…

设计模式 工厂方法_工厂方法设计模式

设计模式 工厂方法工厂方法模式是流行的创作设计模式之一。 它并不特别依赖于工厂对象来创建对象。 而是要在同一类中使用单独的方法来创建对象。 Factory Method模式定义了一个用于创建对象的接口&#xff0c;但是让子类决定如何实例化其对象。 每个子类必须定义其Factory方法…

靖江机器人怎么样_铁饭碗不保?靖江可能消失的12大职业!快看有你的工作没?...

原标题&#xff1a;铁饭碗不保&#xff1f;靖江可能消失的12大职业&#xff01;快看有你的工作没&#xff1f;无人飞机、无人驾驶、智能机器人....你能想象这些充满现代感的高科技正在改变我们的生活吗&#xff1f;在科技高速发展的今天人工智能逐渐能够代替人类的部分工作但&a…