二叉树
先序遍历二叉树的操作定义如下:
若二叉树为空,则空操作;否则
(I)访问根结点;
(2)先序遍历左子树;
(3)先序遍历右子树。
中序遍历二叉树的操作定义如下:
若二叉树为空,则空操作;否则
(I)中序遍历左子树;
(2)访问根结点;
(3)中序遍历右子树。
后序遍历二叉树的操作定义如下:
若二叉树为空,则空操作;否则
(I)后序遍历左子树;
(2)后序遍历右子树;
(3)访问根结点。
例如,图5.5所示的二叉树表示下述表达式
a+b*(c-d)一elf
若先序遍历此二叉树,按访间结点的先后如字将结点排列起来,可得到二叉树的先序序列为
-+ a * b -cd /ef
类似地,中序遍历此二叉树,可得此二叉树的中序序列为
+a b * c - d - e/f
后序遍历此二叉树,可得此二叉树的后序序列为
(5-3)
(5-4)
abed-*+ ef/
完全二叉树:设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,
第 h 层所有的结点都连续集中在最左边
满二叉树:深度为k且有2^k-1个结点的二叉树称为满二叉树
**先序遍历也叫做先根遍历、前序遍历,可记做根左右(二叉树父结点向下先左后右)。遍历树涉及以某种方式遍历所有节点。因为从给定节点中可以有一个以上的下一个节点(它不是线性数据结构),所以,假设顺序计算(非并行),则必须推迟某些节点,以某种方式存储以供以后访问。这通常是通过堆栈(LIFO)或队列(FIFO)完成的。由于树是自引用(递归定义)的数据结构,因此可以通过递归或更确切地说是corecursion来以非常自然和清晰的方式定义遍历。在这些情况下,延迟的节点将隐式存储在调用堆栈中。
本文的程序基本来源于《大话数据结构》,个人感觉是一本非常好的书,推荐去看。
1. 为什么叫前序、后序、中序?
一棵二叉树由根结点、左子树和右子树三部分组成,若规定 D、L、R 分别代表遍历根结点、遍历左子树、遍历右子树,则二叉树的遍历方式有 6 种:DLR、DRL、LDR、LRD、RDL、RLD。由于先遍历左子树和先遍历右子树在算法设计上没有本质区别,所以,只讨论三种方式:
DLR–前序遍历(根在前,从左往右,一棵树的根永远在左子树前面,左子树又永远在右子树前面 )
LDR–中序遍历(根在中,从左往右,一棵树的左子树永远在根前面,根永远在右子树前面)
LRD–后序遍历(根在后,从左往右,一棵树的左子树永远在右子树前面,右子树永远在根前面)
前序遍历(DLR)
中序遍历(LDR)
后序遍历(LRD)
需要注意几点:
根是相对的,对于整棵树而言只有一个根,但对于每棵子树而言,又有自己的根。比如对于下面三个图,对于整棵树而言,A是根,A分别在最前面、中间、后面被遍历到。而对于D,它是G和H的根,对于D、G、H这棵小树而言,顺序分别是DGH、GDH、GHD;对于C,它是E和F的根,三种排序的顺序分别为: CEF、ECF、EFC。是不是根上面的DLR、LDR、LRD一模一样呢~~
整棵树的起点,就如上面所说的,从A开始,前序遍历的话,一棵树的根永远在左子树前面,左子树又永远在右子树前面,你就找他的起点好了。
二叉树结点的先根序列、中根序列和后根序列中,所有叶子结点的先后顺序一样
建议看看文末第3个参考有趣详细的推导
层序遍历
层序遍历嘛,就是按层,从上到下,从左到右遍历,这个没啥好说的。