二叉树,波兰式,逆波兰式,二叉树的遍历
来源:互联网 发布:java 线程池 合并task 编辑:程序博客网 时间:2024/05/22 13:32
原博地址:http://lib.csdn.net/article/datastructure/15516
转载供以后研究
中缀表达式与后缀表达式
中缀表达式(或中缀记法)是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。
与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被计算机解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
与前缀或后缀记法不同的是,中缀记法中括号是必需的。计算过程中必须用括号将操作符和对应的操作数括起来,用于指示运算的次序。
例:
(1)8+4-6*2用后缀表达式表示为:
62*84+-
(2)2*(3+5)-4+7/1用后缀表达式表示为:
35+2*71/4-+
来源: <http://baike.baidu.com/link?url=mAvuPrzHlCr8qOnfwDTbaZON5ZhK69eZfrB0LbND917ZUJXtqrQYEg9tampLYGOEGgLfyTVisO-CjDC5TzZPsq>
中缀表达式转为后缀表达式(又称逆波兰表达式)的方法
逆波兰算法-栈实现
将一个普通的中序表达式转换为逆波兰表达式的一般算法是:
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入逆波兰式的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符优先级大于S1栈栈顶运算符优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,则将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈底。
(4)若取出的字符是“)”,则将距离S1栈栈底最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
完成以上步骤,S2栈便为逆波兰式输出结果。不过S2应做一下逆序处理。便可以按照逆波兰式的计算方法计算了!
//#include<iostream>#include<stdlib.h>#include<stdio.h>#include<stack>#include<math.h>#include<string.h>#definemax100usingnamespacestd;charex[max];/*存储后缀表达式*/ void trans(){/*将算术表达式转化为后缀表达式*/ charstr[max];/*存储原算术表达式*/ charstack[max];/*作为栈使用*/ charch; intsum,i,j,t,top=0; printf("*****************************************\n"); printf("*输入一个求值的表达式,以#结束。*\n"); printf("******************************************\n"); printf("算数表达式:"); i=0;/*获取用户输入的表达式*/ do{ i++; //cin>>str[i];/*此步我用的是C++C语言的话在后面之所以用这个有一点区别都*/ scanf("%c",&str[i]); }while(str[i]!='#'&&i!=max); sum=i; t=1;i=1; ch=str[i];i++; // while(ch!='#') { switch(ch) { case'(':/*判定为左括号*/ top++;stack[top]=ch; break; case')':/*判定为右括号*/ while(stack[top]!='(') { ex[t]=stack[top];top--;t++; } top--; break; case'+':/*判定为加减号*/ case'-': while(top!=0&&stack[top]!='(') { ex[t]=stack[top]; top--; t++; } top++; stack[top]=ch; break; case'*':/*判定为乘除号*/ case'/': while(stack[top]=='*'||stack[top]=='/') { ex[t]=stack[top]; top--; t++; } top++; stack[top]=ch; break; case'':break; default: while(ch>='0'&&ch<='9') {/*判定为数字*/ ex[t]=ch;t++; ch=str[i];i++; } i--; ex[t]='';t++; } ch=str[i];i++; } while(top!=0) { ex[t]=stack[top]; t++;top--; } ex[t]=''; printf("\n\t原来表达式:"); for(j=1;j<sum;j++) printf("%c",str[j]); printf("\n\t逆波兰式:",ex); for(j=1;j<t;j++) printf("%c",ex[j]);} void compvalue(){/*计算后缀表达式的值*/ floatstack[max],d;/*作为栈使用*/ charch; intt=1,top=0;/*t为ex下标,top为stack下标*/ ch=ex[t];t++; while(ch!='') { switch(ch) { case'+': stack[top-1]=stack[top-1]+stack[top]; top--; break; case'-': stack[top-1]=stack[top-1]-stack[top]; top--; break; case'*': stack[top-1]=stack[top-1]*stack[top]; top--; break; case'/': if(stack[top]!=0)stack[top-1]=stack[top-1]/stack[top]; else { printf("\n\t除零错误!\n"); exit(0);/*异常退出*/ } top--; break; default: d=0; while(ch>='0'&&ch<='9') { d=10*d+ch-'0';/*将数字字符转化为对应的数值*/ ch=ex[t];t++; } top++; stack[top]=d; } ch=ex[t]; t++; } printf("\n\t计算结果:%g\n",stack[top]);} intmain(){ trans(); compvalue(); system("pause"); return0;}
来源: <http://baike.baidu.com/link?url=ta18MXKqCaKCW1-OFa1RxHkjXBZpVW3tjsNqoD6BvEwbK0GEfZpS5EB1Et9WPtppOZtC1YLou68aLm8hSQ1Xta>
逆波兰算法-二叉树实现
#include <string> #include <stack> #include <iostream> #include <sstream> #include <iomanip> using namespace std; //节点类 class TNode { public: friend class calculator_tree; string father; TNode *left, *right; TNode() { left = right = NULL; } TNode(string a) { father = a; left = right = NULL; } }; class calculator_tree { public: calculator_tree() { } calculator_tree(string expression) { getexpression(expression); } //获得算术表达式 void getexpression(string expression) { e = expression; } ~calculator_tree() { } //返回中缀表达式 string ShowMiddleExpression() { return e; } //计算函数, 输入为两个数和一个操作符, 返回值为计算结果(字符串形式) string calculate(string num2, string num1, string op) { double n2, n1; string result; stringstream x; x << num2; x >> n2; x.clear(); x << num1; x >> n1; x.clear(); if (op == "+") x << (n2 + n1); if (op == "-") x << (n2 - n1); if (op == "*") x << (n2 * n1); if (op == "/") x << (n2 / n1); x >> result; x.clear(); return result; } //判别符号的优先级 int Priority(char a) { if (a == '(') return 0; else if (a == '+' || a == '-') return 1; else if (a == '*' || a == '/') return 2; return 0; } //用于去除输入中多余的空格 输入为要除去空格的算术表达式 返回去掉空格的算术表达式 string RidSpace(string origin) { string transfer; for (int i = 0; i < origin.length(); i++) { if (origin[i] != ' ') transfer += origin[i]; } return transfer; } //中缀表达式转后缀表达式, 因为要兼容多位数, 括号, 负数和小数等功能, //由于多位数在转为后缀表达式时会分不清, 故在每个数和运算符后面加上一个空格作为区别 //expression为输出的后缀表达式 string MidToLast(string str) { str = RidSpace(str); string expression = ""; string number = ""; char x; stack<char> op; for (int i = 0; i < str.length(); ) { //第一位做特殊处理 判断是否为负号 if (i == 0 && str[i] == '-') { number = "-"; i++; } x = str[i]; //录入数字 if ((x >= '0' && x <= '9') || number == "-" || x == '.') { while ((str[i] >= '0' && str[i] <= '9') || str[i] == '.') { number += str[i]; i++; } expression += number; //加空格以区别 expression += " "; number = ""; continue; } else { //判断是括号还是运算符 if (x == '(') { op.push(x); //判断是否为负号 if (str[i+1] == '-') { number = "-"; i++; } } else { //遇到右括号直接弹出运算符栈里的运算符到表达式中 运算符后加空格以区别 if (x == ')') { while (op.top() != '(') { expression += op.top(); expression += " "; op.pop(); } //弹出右括号 op.pop(); } else { //弹出栈中优先级较高的运算符 运算符后加空格以区别 while (!op.empty() && (Priority(op.top()) >= Priority(x))) { expression += op.top(); expression += " "; op.pop(); } //判断是否为负号 if (str[i+1] == '-') { number = "-"; i++; } //将运算符压入栈 op.push(x); } } } i++; } while (!op.empty()) { expression += op.top(); expression += " "; op.pop(); } return expression; } //获得后缀表达式 string GetLastExpression() { return MidToLast(RidSpace(e)); } //生成一棵二叉树 void makeTree(TNode *&p) { stack <TNode*> Nodes; string le = GetLastExpression(); string tem = ""; for (int i = 0; i < le.length(); ) { while (le[i] != ' ') { tem += le[i]; i++; } //若为数字, 压入结点栈 if (tem.length() > 1 || (tem.length() == 1 && tem[0] >= '0' && tem[0] <= '9')) { p =new TNode(tem); Nodes.push(p); } else { //若为运算符 且栈非空 将栈顶元素拿出来分别作为左子树跟右子树的结点 //处理如-()的情况 if (Nodes.empty()) { tem = "-"; i++; continue; } p = new TNode(tem); if (!Nodes.empty()) { p -> right = Nodes.top(); Nodes.pop(); } if (!Nodes.empty()) { p -> left = Nodes.top(); Nodes.pop(); } Nodes.push(p); } i++; tem = ""; } } //后序遍历二叉树并计算 将计算结果返回 string PostOrder(TNode *p) { if(p) { //假如为符号 执行计算后返回计算结果 if ((p->father).length() == 1 && Priority((p->father)[0])) { PostOrder(p->right); return calculate(PostOrder(p->left), PostOrder(p->right), p->father); } else { //假如为数字, 直接返回 return p->father; } } } private: //存放输入的表达式 string e; };
后缀表达式生成二叉树
转载请注明涞源chengyaogen.blog.chinaunix.net
一、定义
二叉树(binary tree)是一棵每个结点都不能有多于两个儿子的树。
二、数据结构设计
因为一个二叉树结点最多是有两个儿子,所以可以直接链接到他们。树结点的声明在结构上类似双向链表的声明。在声明中,一个结点就是由element(元素)的信息加上两个 到其他结点的引用(left和right)组成的结构
struct BinaryNode
{
Object element; //The data in the node
struct BinaryNode *left; //Left child
struct BinaryNode *right; //Right child
};
三、表达式树
表达式树的树叶是操作数(operand),加常数或变量名字,而其他的结点为操作数(operator)。由于这里所有的操作都是二元的,因此这棵特定的树正好是二叉树,虽然这是最简单的情况,但是结点还是有可能含有多于两个的儿子,这里我们不讨论。
四、构造一棵表达式树
之前我们实现过一个中缀表达式求值的具体程序,在求值过程中需要用两个栈,并且代码并不简单。而这里你会看到,对于表达式树的求值操作却非常简单,甚至只需要两条语句。因为这里大部分操作都是递归定义,二递归函数本身都是很简洁的,甚至比你想象的还要简单,甚至只需要两条语句。因为这里大部分操作都是递归定义,二递归函数本身都是很简洁的,甚至比你想象的还要简单!就像树的遍历操作。三种遍历分别是先序遍历、中序遍历与后序遍历,正好对应表达式的三种形式:前缀型、中缀型与后缀型。其中为大家熟知的是中缀形式,如2+3*(5-4)。前缀型表达式又叫波兰式(Polish Notation),后缀性表达式又叫逆波兰式(Reverse Polish Notation)。他们最早于1920年波兰数学家Jan Lukasiewicz发明,这两种表示方式的最大特点是不需要括号来表明优先级,他们经常用于计算机科学,特别是编译器设计方面。
下面给出一种算法来把后缀表达式转变成表达式树。我们一次一个符号地读入表达式。如果符号是操作数,那么就建立一个单结点树并将它推入栈中。如果符号是操作符,那么就从栈中弹出两棵树T1和T2(T1先弹出)并形成一棵新的树,该树的根就是操作符,它的左、右儿子分别是T2和T1。然后将指向这颗树的指针压入栈中。
下面来看一个例子。设输入为ab+cde+**
前两个符号是操作数,因此创建两棵单结点树并将指向它们的指针压入栈中。
接着,"+"被读入,因此指向两棵树的指针被弹出,形成一棵新的树,并将指向它的指针压入栈中。
然后,c,d和e被读入,在单个结点树创建后,指向对应的树的指针被压入栈中。
接下来读入"+"号,因此两棵树合并。
继续进行,读入"*"号,因此,弹出两棵树的指针合并形成一棵新的树,"*"号是它的根。
最后,读入一个符号,两棵树合并,而指向最后的树的指针被留在栈中。
下面我们来实现以下它吧
#include <stdio.h>#include <stdlib.h>#define MAX 100//树结点的设计typedef struct node{ //数字和运算符 union { char operator; int data; }; struct node *lchild; struct node *rchild; }TreeNode;//树栈的设计typedef struct{ TreeNode *buf[MAX]; int n; }TreeStack;//创建空栈TreeStack *create_empty_stack(){ TreeStack *pstack; pstack = (TreeStack *)malloc(sizeof(TreeStack)); pstack->n = -1; return pstack;}//入栈int push_stack(TreeStack *p,TreeNode *data){ p->n ++; p->buf[p->n] = data; return 0;}//出栈TreeNode *pop_stack(TreeStack *p){ TreeNode *data; data = p->buf[p->n]; p->n --; return data;}//判断空栈int is_empty_stack(TreeStack *p){ if(p->n == -1) { return 1; }else{ return 0; }}//后缀表达式树的创建TreeNode *create_express_tree(char *str,TreeStack *p){ int i = 0; TreeNode *current; TreeNode *left,*right; while(str[i]) { if(str[i] == ' ') { i ++; continue; } if(str[i] >= '0' && str[i] <= '9') { current = (TreeNode *)malloc(sizeof(TreeNode)); current->data = str[i] - '0'; current->lchild = current->rchild = NULL; push_stack(p,current); }else{ current = (TreeNode *)malloc(sizeof(TreeNode)); current->operator = str[i]; right = pop_stack(p); left = pop_stack(p); current->lchild = left; current->rchild = right; push_stack(p,current); } i ++; } return p->buf[p->n];}//打印结点void print_node(TreeNode *p){ if(p->lchild == NULL && p->rchild == NULL) { printf("%d ",p->data); }else{ printf("%c ",p->operator); } return;}//访问结点int vist_node(TreeNode *p){ print_node(p); return 0;}//树的后序遍历int PostOrder(TreeNode *p){ if(p != NULL) { PostOrder(p->lchild);//左 PostOrder(p->rchild);//右 vist_node(p);//根 } return 0;}//树的中序遍历int InOrder(TreeNode *p){ if(p != NULL) { InOrder(p->lchild);//左 vist_node(p);//根 InOrder(p->rchild);//右 } return 0;}//树的前序遍历int PreOrder(TreeNode *p){ if(p != NULL) { vist_node(p);//根 PreOrder(p->lchild);//左 PreOrder(p->rchild);//右 } return 0;}/队列的设计struct _node_{ TreeNode *data; struct _node_ *next;};typedef struct{ struct _node_ *front; struct _node_ *rear; }Queue;//创建空队列Queue *create_empty_queue(){ struct _node_ *pnode; Queue *qhead; qhead = (Queue *)malloc(sizeof(Queue)); pnode = (struct _node_ *)malloc(sizeof(struct _node_)); pnode->next = NULL; qhead->front = qhead->rear = pnode; return qhead; }//入队int EnterQueue(Queue *qhead,TreeNode *data){ struct _node_ *temp; temp = (struct _node_ *)malloc(sizeof(struct _node_ *)); temp->data = data; temp->next = NULL; qhead->rear->next = temp; qhead->rear = temp; return 0; }//出队TreeNode *DeleteQueue(Queue *qhead){ struct _node_ *temp; temp = qhead->front; qhead->front = temp->next; free(temp); temp = NULL; return qhead->front->data;}//队列为空int is_empty_queue(Queue *qhead){ if(qhead->front == qhead->rear) return 1; else return 0;}//树的层次遍历int NoOrder(TreeNode *p){ Queue *qhead; TreeNode *pdata; qhead = create_empty_queue(); EnterQueue(qhead, p); while(!is_empty_queue(qhead)) { pdata = DeleteQueue(qhead); vist_node(pdata); if(pdata->lchild)EnterQueue(qhead,pdata->lchild); if(pdata->rchild)EnterQueue(qhead,pdata->rchild); } return 0;}int main(){ TreeNode *thead; TreeStack *pstack; int i = 0; char buf[100]; while((buf[i++] = getchar()) != '\n' && i < 100); buf[i-1] = 0; pstack = create_empty_stack(); thead = create_express_tree(buf,pstack); printf("PostOrder:: "); PostOrder(thead); printf("\n"); printf("InOrder:: "); InOrder(thead); printf("\n"); printf("PreOrder:: "); PreOrder(thead); printf("\n"); printf("NoOrder::"); NoOrder(thead); printf("\n"); return 0;}
0 0
- 二叉树,波兰式,逆波兰式,二叉树的遍历
- 用二叉树判断逆波兰表达式
- 如何将中缀式转化成前缀式和后缀式(波兰和逆波兰)结合二叉树(适合数据结构方面的理解)
- 几个简单递归问题(菲波那契数列 ,二叉树,逆波兰式)
- 二叉树解析实现逆波兰公式算法
- 二叉树解析实现逆波兰公式算法
- 二叉树解析实现逆波兰公式算法
- java 二叉树(十一)表达式与逆波兰序列
- 波兰式,逆波兰式
- 栈的应用 - 波兰式与逆波兰式
- 波兰式和逆波兰的相互转化
- 逆波兰式的生成
- 波兰式和逆波兰式
- 逆波兰式与波兰式
- 波兰式转换为逆波兰式
- 逆波兰式
- 逆波兰式算法
- java 逆波兰式
- 从Vuex中取出数组赋值给新的数组,新数组push时报错
- Kotlin:Android世界的Swift
- 工作流
- JavaScript立即执行函数表达式(IIFE)
- PowerShell命令
- 二叉树,波兰式,逆波兰式,二叉树的遍历
- Eclipse 连接Hadoop Connection refused 问题
- 【转】我们培养了很多高学历的野蛮人
- CSS3属性之Transitions
- 自适应阈值Canny边缘检测
- gdb实用操作命令
- 数据结构::关于迭代器失效
- vim快捷键
- ******英文字母和中文汉字在不同字符集编码下的字节数 英文字母:******