二叉树非递归遍历——压栈分析


非递归的具体代码实现参见: 👉这里

先序

m
A
B
C
D
E
n

先序压栈:先输出,再压左子树,后pop左子树,pop根,压右子树。

输出mACnNULLBDNULLE
mA
m
C
A
m
A
m
mn
m
mNULLBD
B
BNULLEend

对于任何一个子树来说:先压根,再压左子树,先弹出所有左子树,再弹出根,栈空,最后压右子树,弹出所有右子树(其中栈会有几次空)。

pop左子树右子树
stack左子树
右子树

与中序的不同在于,其在压入前输出,实现了与压入顺序相同的输出顺序LNR。


中序

m
A
B
C
D
E
n

中序:先压左子树,先pop后输出,再压右子

输出CAnmDBE
C
A
m
A
m
mn
m
mNULLD
B
BNULLEend

对于任何一个子树来说:先压根再压左子树,先弹出所有左子树,再弹出根,栈空,最后压右子树,弹所有右子树(其中栈会有几次空)。

pop左子树右子树
stack左子树
右子树

与先序的不同在于,其在pop后输出,实现了与压入顺序相反的输出顺序NLR


后序

m
A
B
C
D
E
n
输出CnADEBm
C
A
m
A
m
n
A
m
A
m
mD
B
m
B
m
E
B
m
B
m
mend

后序的栈中,任何一个时刻,都包含了栈顶及其到根的所有祖先!
从根压到叶,再从叶pop到根。每次左pop了,就去压右,即总是左子出栈再压右子树。

pop左子树右子树
stack左子树
右子树

根据上面分析:

  1. 压栈顺序相同:根、左子树、右子树。
  2. 出栈顺序不同:先/中:左子树,根,右子树。
    \qquad\qquad\qquad 后: \quad 左子树,右子树,根。
  3. 兄弟结点不会同时在栈中,因为总是左子树pop了,再push右子树。
  4. 后序的栈中,任何时候都包含了栈顶结点到根的所有祖先(即栈顶到根的路径)
  5. 先/中 压栈、出栈方式相同,先:先输出后push,中:先pop后输出。
  6. 先/中都会在左子树与根全出栈后,出现栈空的情况!而后序在处理 最后一个结点(根)之前都不会空栈。
  7. 承上,while(p||!isEmpty(S))为什么需要p ?
    (1)S一开始是空的(根纳入while里面处理了)
    (2) 对于先/中都会在之后再次出现若干次S空的状态。

附:层序

层序使用队列,逻辑清晰简单,层序可以用来实现很多东西,比如求树高,树宽,某层结点数,每层结点数,是否完全二叉树…

T
A
B
C
D
E
F
front rear ↔ \leftrightarrow 输出层数
T #
0 1
m第一层
T A B #
 1  3
A、Bm第二层
T A B C D #
  2   5
B、C、nA
T A B C D E F#
   3   7
C、n、D、EB第三层
T A B C D E F#
    4  7
n、D、EC
T A B C D E F#
     5 7
D、En
T A B C D E F #
      6 7
ED
E

我们可以发现,若将结点编号,根为1,每次front==最右边结点时,说明层数加一。
以此可以计算总层数。

T
A
B
C
D
E
#
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值