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

文章目录

    • 先序
    • 中序
    • 后序
    • 附:层序

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

先序

m
A
B
C
D
E
n

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

输出 m A C n NULL B D NULL E
m A
m
C
A
m
A
m
m n
m
m NULL B D
B
B NULL E end

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

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

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


中序

m
A
B
C
D
E
n

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

输出 C A n m D B E
C
A
m
A
m
m n
m
m NULL D
B
B NULL E end

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

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

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


后序

m
A
B
C
D
E
n
输出 C n A D E B m
C
A
m
A
m
n
A
m
A
m
m D
B
m
B
m
E
B
m
B
m
m end

后序的栈中,任何一个时刻,都包含了栈顶及其到根的所有祖先!
从根压到叶,再从叶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、B m 第二层
T A B C D #
  2   5
B、C、n A
T A B C D E F#
   3   7
C、n、D、E B 第三层
T A B C D E F#
    4  7
n、D、E C
T A B C D E F#
     5 7
D、E n
T A B C D E F #
      6 7
E D
E

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

T
A
B
C
D
E
#

你可能感兴趣的:(二叉树,二叉树,数据结构,栈,leetcode)