树的遍历应该是一个很基础的问题,但如果要求选手写算法一次通过却不容易,所以又拿来好好研究(熟悉)一番,力求以后再遇到这样的问题能够快速准确地解决。
以下给出了四种遍历的一种或多种解法,为了快速表达,使用了python语言。四种遍历分别是层序、前序、中序和后序,所谓层序就是由上到下一次遍历一层,所谓前中后则是父节点的打印顺序,N代表父节点,LR代表左右子节点的话,NLR为前序,LNR为中序,LRN为后序。
节点的表示
接下来的代码都对如下定义的节点组成的树作操作:
1 2 3 4 5 6 7 8
| class Node: def __init__(self, name, left, right): self.name = name self.left = left self.right = right def __str__(self): return self.name
|
前中后序-递归
递归的方法是最简单也是最容易想到的方法,因为二叉树的结构是固定的,遍历的规则也一定的,每到一个节点上作相同的处理即可。
前序:
- 如节点不为空,打印本身
- 如左不为空,进入左
- 如右不为空,进入右
表现为代码就是:
1 2 3 4 5 6 7 8
| def recnlr(node): if node is None: return print node, if node.left: recnlr(node.left) if node.right: recnlr(node.right)
|
打印结果为:A B D C E G H F I
接下来的中、后序都本分类似:
中序
1 2 3 4 5 6 7 8
| def reclnr(node): if node is None: return if node.left: reclnr(node.left) print node, if node.right: reclnr(node.right)
|
输出结果:D B A G E H C F I
后序
1 2 3 4 5 6 7 8
| def reclrn(node): if node is None: return if node.left: reclrn(node.left) if node.right: reclrn(node.right) print node,
|
输出结果:D B G H E I F C A
非递归方法
非递归方法才是相对比较困难的,像很多递归问题的非递归解法一样,这里我们也要用到栈。因为树的结构是不确定的,拿前序的方法来举例,本来的顺序是NLR,到达一个节点,打印N之后,就应该进入L,处理完L后处理R,但是无法确定何时能够回到R,所以我们在进入L之前应该先将R保存到栈中,这有点类似函数调用时的保存现场,都是利用栈的先进后出的特性来还原真实过程。
前序
1 2 3 4 5 6 7 8 9
| def stacknlr(root): s = [root] while s: node = s.pop() while node: print node, if node.right: s.append(node.right) node = node.left
|
输出:A B D C E G H F I
中序
中序和前序相分类似
1 2 3 4 5 6 7 8 9 10
| def stacklnr(root): node = root s = [] while node or s: while node: s.append(node) node = node.left node = s.pop() print node, node = node.right
|
result:D B A G E H C F I
后序
后序就相对复杂一些,因为父节点是最后打印的,之前要进入左右子节点再返回,所以并不能一次压栈出栈就完成,而是需要判断更多的条件。
以下情况下,可以打印当前节点:
- 左右节点为空
- 从左节点返回,而右子节点为空
- 从右节点返回
以下是程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def stacklrn(root): pre = None s = [root] while s: node = s.pop() if node.left is None and node.right is None or \ node.right is not None and node.right == pre or \ node.left == pre and node.right is None: print node, pre = node elif node.left and node.left != pre: s.append(node) s.append( node.left) elif node.right: s.append(node) s.append( node.right)
|
结果:D B G H E I F C A
层序-队列
层序是比较特殊的,不适合和递归也不适合栈,但是用队列却十分简单。从根节点开始,打印一个节点时将其左右子节点加入队列,直到队列为空。
1 2 3 4 5 6 7 8 9 10 11
| def tier(root): import Queue q = Queue.Queue(maxsize=0) q.put(root) while not q.empty(): c = q.get() print c, if c.left: q.put(c.left) if c.right: q.put(c.right)
|
输出:A B C D E F G H I
附录 完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
| __author__ = 'chen' class Node: def __init__(self, name, left, right): self.name = name self.left = left self.right = right def __str__(self): return self.name def recnlr(node): if node is None: return print node, if node.left: recnlr(node.left) if node.right: recnlr(node.right) def reclnr(node): if node is None: return if node.left: reclnr(node.left) print node, if node.right: reclnr(node.right) def reclrn(node): if node is None: return if node.left: reclrn(node.left) if node.right: reclrn(node.right) print node, def stacknlr(root): s = [] node = root while node: while node: print node, if node.right: s.append(node.right) node = node.left if s: node = s.pop() def stacknlr3(root): s = [root] while s: node = s.pop() while node: print node, if node.right: s.append(node.right) node = node.left def stacknlr2(root): s = [] node = root while node: print node, if node.left: if node.right: s.append(node.right) node = node.left elif node.right: node = node.right elif s: node = s.pop() else: break def stacklnr(root): node = root s = [] while node or s: while node: s.append(node) node = node.left node = s.pop() print node, node = node.right def tier(root): import Queue q = Queue.Queue(maxsize=0) q.put(root) while not q.empty(): c = q.get() print c, if c.left: q.put(c.left) if c.right: q.put(c.right) def stacklrn(root): pre = None s = [root] while s: node = s.pop() if node.left is None and node.right is None or \ node.right is not None and node.right == pre or \ node.left == pre and node.right is None: print node, pre = node elif node.left and node.left != pre: s.append(node) s.append( node.left) elif node.right: s.append(node) s.append( node.right) if __name__ == "__main__": root = Node("A", Node("B", Node("D", None, None), None), Node("C", Node("E", Node("G", None, None), Node("H", None, None)), Node("F", None, Node("I", None, None)))) print "recursive nlr:", recnlr(root) print "" print "recursive lnr:", reclnr(root) print "" print "recursive lrn:", reclrn(root) print "" print "stack nlr3:", stacknlr3(root) print "" print "stack nlr2:", stacknlr2(root) print "" print "stack lnr:", stacklnr(root) print "" print "stack lrn:", stacklrn(root) print "" print "tier lnr:", tier(root) print ""
|
output:
1 2 3 4 5 6 7 8 9
| chen@vaio:/data/PycharmProjects/tree$ python tree.py recursive nlr: A B D C E G H F I recursive lnr: D B A G E H C F I recursive lrn: D B G H E I F C A stack nlr3: A B D C E G H F I stack nlr2: A B D C E G H F I stack lnr: D B A G E H C F I stack lrn: D B G H E I F C A tier lnr: A B C D E F G H I
|