原文,转载如下:

用到了栈,并且递归实现了中序遍历,后序遍历,前序遍历。

同时应该学会union的使用方法。


基础知识:

一、表达式树
表达式树的树叶是操作数(operand),加常数或变量名字,而其他的结点为操作数(operator)。由于这里所有的操作都是二元的,因此这棵特定的树正好是二叉树,虽然这是最简单的情况,但是结点还是有可能含有多于两个的儿子,这里我们不讨论。


二、构造一棵表达式树

之前我们实现过一个中缀表达式求值的具体程序,在求值过程中需要用两个栈,并且代码并不简单。而这里你会看到,对于表达式树的求值操作却非常简单,甚至只需要两条语句。因为这里大部分操作都是递归定义,二递归函数本身都是很简洁的,甚至比你想象的还要简单,甚至只需要两条语句。因为这里大部分操作都是递归定义,二递归函数本身都是很简洁的,甚至比你想象的还要简单!就像树的遍历操作。三种遍历分别是先序遍历、中序遍历与后序遍历,正好对应表达式的三种形式:前缀型、中缀型与后缀型。其中为大家熟知的是中缀形式,如2+3*(5-4)。前缀型表达式又叫波兰式(Polish Notation),后缀性表达式又叫逆波兰式(Reverse Polish Notation)。他们最早于1920年波兰数学家Jan Lukasiewicz发明,这两种表示方式的最大特点是不需要括号来表明优先级,他们经常用于计算机科学,特别是编译器设计方面。

下面给出一种算法来把后缀表达式转变成表达式树。我们一次一个符号地读入表达式。如果符号是操作数,那么就建立一个单结点树并将它推入栈中。如果符号是操作符,那么就从栈中弹出两棵树T1和T2(T1先弹出)并形成一棵新的树,该树的根就是操作符,它的左、右儿子分别是T2和T1。然后将指向这颗树的指针压入栈中。

下面来看一个例子。设输入为ab+cde+**

前两个符号是操作数,因此创建两棵单结点树并将指向它们的指针压入栈中。
接着,"+"被读入,因此指向两棵树的指针被弹出,形成一棵新的树,并将指向它的指针压入栈中。

然后,c,d和e被读入,在单个结点树创建后,指向对应的树的指针被压入栈中。
接下来读入"+"号,因此两棵树合并。
继续进行,读入"*"号,因此,弹出两棵树的指针合并形成一棵新的树,"*"号是它的根。
最后,读入一个符号,两棵树合并,而指向最后的树的指针被留在栈中。


[cpp] view plain copy
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #defineMAX100
  4. /*树结点的设计*/
  5. typedefstructnode
  6. {
  7. /*数字和运算符*/
  8. union
  9. {
  10. charoperator;
  11. intdata;
  12. };
  13. structnode*lchild;
  14. structnode*rchild;
  15. }TreeNode;
  16. /*树栈*/
  17. typedefstructTree_Stack
  18. {
  19. TreeNode*buf[MAX];
  20. intn;
  21. }TreeStack;
  22. /*创建空栈*/
  23. TreeStack*create_empty_stack()
  24. {
  25. TreeStack*pstack;
  26. pstack=(TreeStack*)malloc(sizeof(TreeStack));
  27. pstack->n=-1;
  28. returnpstack;
  29. }
  30. /*入栈*/
  31. intpush_stack(TreeStack*p,TreeNode*data)
  32. {
  33. p->n++;
  34. p->buf[p->n]=data;
  35. return0;
  36. }
  37. /*出栈*/
  38. TreeNode*pop_stack(TreeStack*p)
  39. {
  40. TreeNode*data;
  41. data=p->buf[p->n];
  42. p->n--;
  43. returndata;
  44. }
  45. /*判断栈空*/
  46. intis_empty_stack(TreeStack*p)
  47. {
  48. if(p->n==-1)
  49. return1;
  50. else
  51. return0;
  52. }
  53. /*创建后缀表达式树*/
  54. TreeNode*create_express_tree(char*str,TreeStack*p)
  55. {
  56. inti=0;
  57. TreeNode*current;
  58. TreeNode*left,*right;
  59. while(str[i])
  60. {
  61. if(str[i]>='0'&&str[i]<='9')
  62. {
  63. current=(TreeNode*)malloc(sizeof(TreeNode));
  64. current->data=str[i]-'0';
  65. current->lchild=NULL;
  66. current->rchild=NULL;
  67. push_stack(p,current);
  68. }
  69. else
  70. {
  71. current=(TreeNode*)malloc(sizeof(TreeNode));
  72. current->operator=str[i];
  73. right=pop_stack(p);
  74. left=pop_stack(p);
  75. current->lchild=left;
  76. current->rchild=right;
  77. push_stack(p,current);
  78. }
  79. i++;
  80. }
  81. returnp->buf[p->n];
  82. }
  83. /*打印结点*/
  84. voidprint_node(TreeNode*p)
  85. {
  86. if(p->lchild==NULL&&p->rchild==NULL)
  87. printf("%d",p->data);
  88. else
  89. printf("%c",p->operator);
  90. }
  91. /*访问结点*/
  92. intvisit_node(TreeNode*p)
  93. {
  94. print_node(p);
  95. return0;
  96. }
  97. /*树的后序遍历*/
  98. voidpostorder(TreeNode*p)
  99. {
  100. if(p!=NULL)
  101. {
  102. postorder(p->lchild);
  103. postorder(p->rchild);
  104. visit_node(p);
  105. }
  106. }
  107. /*树的中序遍历*/
  108. voidInorder(TreeNode*p)
  109. {
  110. if(p!=NULL)
  111. {
  112. Inorder(p->lchild);
  113. visit_node(p);
  114. Inorder(p->rchild);
  115. }
  116. }
  117. /*树的前序遍历*/
  118. voidPreOrder(TreeNode*p)
  119. {
  120. if(p!=NULL)
  121. {
  122. visit_node(p);
  123. PreOrder(p->lchild);
  124. PreOrder(p->rchild);
  125. }
  126. }
  127. intmain()
  128. {
  129. TreeNode*thead;
  130. TreeStack*pstack;
  131. inti=0;
  132. charbuf[100];
  133. scanf("%s",buf);
  134. pstack=create_empty_stack();
  135. thead=create_express_tree(buf,pstack);
  136. printf("postorder:");
  137. postorder(thead);
  138. printf("\n");
  139. printf("Inorder:");
  140. Inorder(thead);
  141. printf("\n");
  142. printf("PreOrder:");
  143. PreOrder(thead);
  144. printf("\n");
  145. return0;
  146. }

测试结果如下:

【数据结构】后缀表达式-->表达式树的更多相关文章

  1. ios – 嵌套递归函数

    我试图做一个嵌套递归函数,但是当我编译时,编译器崩溃.这是我的代码:编译器记录arehere解决方法有趣的…它似乎也许在尝试在定义之前捕获到内部的引用时,它是bailing?以下修复它为我们:当然没有嵌套,我们根本没有任何问题,例如以下工作完全如预期:我会说:报告!

  2. ios – Objective-C compareTo:

    有没有一个比较Objective-C中的两个对象的标准机制?我知道isEqual方法,但我并不是在寻找完全相同的方式,而是比较少于/多于/等于某种比较.在Java中,我们有compareto:这样做,Objective-C中有什么吗?

  3. 二 Swift学习之基本运算符

    二Swift学习之基本运算符————–借鉴老码团队翻译组-Tyrion1.1术语运算符有一元、二元和三元运算符。三元运算符操作三个操作对象,和C语言一样,Swift只有一个三元运算符,就是三目运算符(a?这不同于上面提到的自增和自减运算符。无疑空合运算符(??由于userDefinedColorName是一个可选类型,我们可以使用空合运算符去判断其值。

  4. 初识Swift集合之字典集合

    这个函数也会返回被替换或者增加的值。

  5. swift与Objective-C的互用性

    在Objective-C中,你用一个空的选项设置标示恒为零。由于简单的用于定义常量的宏会被直接被映射成Swift全局量,Swift编译器会自动引进在C或Objective-C源文件中定义的简单宏。您在C和Objective-C使用复杂的宏以避免类型检查的限制,或避免重新键入大量的样板代码。因此,在C和Objective-C源文件中定义的复杂宏在Swift是不能使用的。编译配置Swift代码和C、Objective-C代码被有条件地,以不同方式编辑。

  6. swift的一些知识点演练

    表示可以有值,也可以没有值//?如果对象为空,就不会调用后面的方法,感觉上和oc中给nil发送消息类似varstr:Nsstring?str="hello"//打印可选项的时候,同时会输出一个Optional,提示开发者,这是一个可选项println(str?.length)letl=10//目前的代码存在什么风险?如果str没有设置初始值,会直接崩溃//苹果把判断对象是否有内容的工作交给了程序员//letlen=l+str!用来快速判断对象是否为nilletlen2=l+(str?0)//以下代码和上面

  7. Swift运算符

    Swift运算符1.赋值运算符“=”用于将一个变量,常量或表达式的值赋值给另一个变量。算术运算符“+”“-”“*”“/”“%”“++”“–”2.溢出运算符1.溢出加“&+”2.溢出减“&-”3.溢出乘“&*”4溢出除“&/”5溢出求余“&%”3.位运算符4.范围运算符本文内容来自《疯狂讲义》

  8. swift笔记-赋值运算符

    复杂些的运算例如逻辑与运算符&&,或让i值加1的便捷自增运算符++i等。Swift支持大部分标准C语言的运算符,且改进许多特性来减少常规编码错误。当然允许你使用Swift的溢出运算符来实现溢出。本章节只描述了Swift中的基本运算符,高级运算符包含了高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。三元运算符操作三个操作对象,和C语言一样,Swift只有一个三元运算符,就是三目运算符(a?

  9. swift override --有一个递归问题未解决

    classca{varcount:Int{get{return1;}set{self.count=newValue;}}funcdescribe()->String{return"ca";}}classcb:ca{overridefuncdescribe()->String{return"cb";}overridevarcount:Int{get{return2;}set{//引起了递归调用,未找

  10. [翻译]Swift编程语言——基本操作符

    基本操作符操作符就是一个简单的符号或者短语,你可以用他们来检查、改变、组合数据。Swift支持标准C的大多数操作符而且有若干改进可以避免代码错误。算数运算符会检测并且不接受溢出的数据,你可以选用Swfit的溢出操作符预防这种情况出现。像C一样,Swift允许你对浮点数取余,同时Swfit也提供了两个C没有的范围操作符(a..术语操作符有一元、二元以及三元的:一元操作符只有一个操作对象(比如-a)。

随机推荐

  1. 【数据结构】单调栈

    显然,每个发射站发来的能量有可能被0或1或2个其他发射站所接受,特别是为了安全,每个发射站接收到的能量总和是我们很关心的问题。由于数据很多,现只需要你帮忙计算出接收最多能量的发射站接收的能量是多少。输入输出格式输入格式:第1行:一个整数N;第2到N+1行:第i+1行有两个整数Hi和Vi,表示第i个人发射站的高度和发射的能量值。输入输出样例输入样例:34235610输出样例:7题解中有讲解代码实现

  2. BZOJ 1798 [Ahoi2009] Seq 维护序列seq [线段树+多重标记下传]【数据结构】

    有长为N的数列,不妨设为a1,a2,…Input第一行两个整数N和P。第二行含有N个非负整数,从左到右依次为a1,aN,。表示把所有满足t≤i≤g的ai改为ai×c。操作2:“2tgc”。同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。Output对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。SampleInput7431234567512553242379313347SampleOutput2358HINT初始时数列为。对第5次操作,和为29+34+15+16=

  3. 陈越《数据结构》第一讲 基本概念

    陈越《数据结构》第一讲基本概念1什么是数据结构1.1引子例子:如何在书架上摆放图书?数据结构是:1.数据对象在计算机中的组织方式;2.数据对象必定与一系列加在其上的操作相关联;3.完成这些操作所用的方法就是算法。抽象数据类型数据类型-数据对象集;-数据集合相关联的操作集。抽象-与存放数据的机器无关;-与数据存储的物理结构无关;-与实现操作的算法和编程语言均无关。

  4. 陈越《数据结构》第二章 线性结构

    表中元素个数称为线性表的长度;线性表没有元素时,称为空表;表起始位置称表头,表结束位置称表尾。插入和删除操作只能在链栈的栈顶进行。

  5. 【数据结构】

    非线性结构:线性结构的元素之间具有线性关系,非线性结构中的元素之间不再是序列的关系,他们呈现的是更复杂的层次关系,即一个数据元素有且仅有一个直接前驱,但可有另个或者多个直接后继,显然比序列关系复杂常见非线性结构:树,图散列表PHP中的hashtable就是哈希表就是由数组和链表组成,一个长度为16的数组中,每个元素存储的是一个链表的头结点。

  6. 【数据结构】【C++STL】FIFO队列&amp;优先队列

    首先都需要打头文件queueFIFO队列是先进先出的就好像排队一样STL定义FIFO队列优先队列的话是有优先级存在的STL定义优先队列定义方式都是大根堆FIFO队列和优先队列都有一些操作COYG

  7. 【数据结构】 堆

    自底向上://增加/减少已有节点值Heap_Increase_Key//向堆插入新的节点HeapInsert自顶向下://替换堆顶后,维持堆函数KeepHeap//弹出堆顶函数Pop

  8. 【数据结构】链表

    线性表的顺序存储结构有存储密度高及能够随机存取等优点,但存在以下不足:线性表的链式存储(单链表)的实现单向循环链表的实现

  9. 伸展树(SPLAY)个人总结+模板 [平衡树]【数据结构】【模板】

    前言最近3个月内,无论是现场赛还线上赛中SPLAY出现的概率大的惊人啊啊啊!!!然而不会的我就GG了,同时发现大家都会SPLAY,,,,然后就学习了一波。——————————————————————————-附上整体代码-md贴上来太卡了,去题解里看吧维护序列的维护一堆数的

  10. BZOJ 1895 &amp; POJ 3580 supermemo [SPLAY]【数据结构】

    Ay}Ttimes.Forexample,performing“REVOLVE242”on{1,5}INSERTxP:insertPafterAx.Forexample,performing“INSERT24”on{1,5}DELETEx:deleteAx.Forexample,performing“DELETE2”on{1,5}MINxy:querytheparticipantwhatistheminimumnumberinsub-sequence{Ax…Ay}.Forexample,thecorrec

返回
顶部