先序压栈:先输出,再压左子树,后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。
中序:先压左子树,先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
输出 | 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 | 根 | 左子树 根 |
根 | 右子树 根 |
根 |
根据上面分析:
while(p||!isEmpty(S))
为什么需要p ?层序使用队列,逻辑清晰简单,层序可以用来实现很多东西,比如求树高,树宽,某层结点数,每层结点数,是否完全二叉树…
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==最右边结点时,说明层数加一。
以此可以计算总层数。