输出遍历序列实际上就是将遍历中的print语句改成储存在结果列表中即可,这里作为练习都写了一遍。
先序遍历
迭代
栈
入栈出栈顺序
# 先序遍历打印
def preorderTraversal(root):
if not root:
return
stack = [root]
while stack:
cur = stack.pop()
print(cur.val)
if cur.right:
stack.append(cur.right)
if cur.left:
stack.append(cur.left)
# 输出先序遍历序列
def preorderTraversal(root):
res = []
if not root:
return res
stack = [root]
while stack:
cur = stack.pop()
res.append(cur.val)
if cur.right:
stack.append(cur.right)
if cur.left:
stack.append(cur.left)
return res
递归
# 打印二叉树
def preorderTraversal(root):
if not root:
return
print(root.val)
preorderTraversal(root.left)
preorderTraversal(root.right)
# 输出先序遍历序列
res = []
def preorderTraversal(root):
if not root:
return
res.append(root.val)
preorderTraversal(root.left)
preorderTraversal(root.right)
print(res)
中序遍历
迭代
# 打印中序遍历结果
def inorderTraverse(root):
stack = []
while stack or root:
while root:
stack.append(root)
root = root.left
root = stack.pop()
print(root.val)
root = root.right
# 输出中序遍历序列
def inorderTraverse(root):
res= []
stack = []
while stack or root:
while root:
stack.append(root)
root = root.left
root = stack.pop()
res.append(root.val)
root = root.right
return res
递归
#打印中序遍历结果
def inorderTraverse(root):
if not root:
return
inorderTraverse(root.left)
print(root.val)
inorderTraverse(root.right)
# 输出中序遍历序列
res = []
def inorderTraverse(root):
if not root:
return
inorderTraverse(root.left)
res.append(root.val)
inorderTraverse(root.right)
后序遍历
迭代
后序遍历的最终结果做逆序,就是先序遍历中交换访问左孩子和右孩子的顺序的结果。因此只要把先序遍历中左右子树的访问顺序对调,最后在做一个逆序就得到后序遍历的结果。
# 打印后序遍历结果
# 使用两个栈结构
# 第一个栈进栈顺序:左节点->右节点->根节点
# 第一个栈弹出顺序: 根节点->右节点->左节点(先序遍历栈弹出顺序:根->左->右)
# 第二个栈存储为第一个栈的每个弹出依次进栈
# 最后第二个栈依次出栈
def postorderTraverse(root):
if not root:
return
stack1, stack2 = [root], []
while stack1:
root = stack1.pop()
stack2.append(root)
if root.left:
stack1.append(root.left)
if root.right:
stack1.append(root.right)
while stack2:
print(stack2.pop().val)
def postorderTraverse(root):
if not root:
return
stack1, stack2 = [root], []
while stack1:
root = stack1.pop()
stack2.append(root)
if root.left:
stack1.append(root.left)
if root.right:
stack1.append(root.right)
return [stack2[i].val for i in range(len(stack2)-1, -1, -1)]
递归
队列
# 打印遍历结果
def postorderTraverse(root):
if not root:
return
postorderTraverse(root.left)
postorderTraverse(root.right)
print(root.val)
# 输出后序遍历序列
res = []
def postorderTraverse(root):
if not root:
return
postorderTraverse(root.left)
postorderTraverse(root.right)
res.append(root.val)
层次遍历
迭代
def layerTraverse(root):
if not root:
return
queue = []
queue.append(root)
while queue:
cur = queue.pop(0)
print(cur.val)
# 输出遍历序列时,只需要增加结果列表,并将上句改成res.append(cur.val)
if cur.left:
queu.append(cur.left)
if cur.right:
queue.append(cur.right)
广度优先搜索BFS
就是层次遍历
应用
问题描述:将二叉树的每一层以列表的形式返回,最终返回结果是由各层列表组成的列表
想法:整体思路还是层次遍历,问题的关键在于如何区分不同层的元素,因为可能二叉树不是完全二叉树,不能简单的使用每一层节点的数量进行判断。
法1
使用不同的序列存储当前层和下一层的节点,当前层访问结束后令其等于下一层的节点列表
def printlayer(root):
ans = []
if not root:
return ans
queue = [root]
while queue:
#当前层节点的值列表
curval = []
# 下一层节点
nextqueue = []
for cur in queue:
curval.append(cur.val)
if cur.left:
nextqueue.append(cur.left)
if cur.right:
nextqueue.append(cur.right)
ans.append(curval)
queue = nextqueue
return ans
法2
在遍历当前层前,记录当前层节点的个数,只访问指定数目的节点
def printlayer(root):
ans = []
if not root:
return ans
queue = [root]
while queue:
curval = []
curlength = len(queue)
for i in range(curlength):
cur = queue.pop(0)
curval.append(cur.val)
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
ans.append(curval)
return ans
深度优先搜索DFS
深度优先搜索对应的就是先序遍历、中序遍历要和后序遍历三种遍历方式
常见的使用是先序遍历的方式。
应用
返回从根节点到叶子节点的所有路径,每条路径为一个列表
法1
使用深度优先搜索递归实现。递归函数的含义是:给出当前节点以及到达当前节点的路径,从当前节点出发先序遍历,只有当遇到叶子节点时才将路径放入最终的结果中。
def construct_paths(root, path):
if root:
path += str(root.val)
if not root.left and not root.right:
#当前节点为叶子节点,将路径加入最终的结果中
paths.append(path)
else:
# 当前节点不是叶子节点,继续递归遍历
path += '->'
construct_paths(root.left, path)
construct_paths(root.right, path)
paths = []
construct_paths(root, '')
法2
使用深度优先搜索迭代实现
class Solution {
fun binaryTreePaths(root: TreeNode?): List<String> {
val result = LinkedList<String>()
val stack: Deque<TreeNode> = LinkedList()
val helperStack: Deque<StringBuilder> = LinkedList<StringBuilder>()
if (null != root) {
stack.push(root)
helperStack.push(StringBuilder())
}
while (!stack.isEmpty()) {
val node = stack.pop()
val path = helperStack.pop()
path.appendChar(node.`val`)
if (null == node.left && null == node.right) {
// 到达叶子节点
result.add(path.toString())
} else {
if (null != node.right) {
stack.push(node.right)
helperStack.push(StringBuilder(path))
}
if (null != node.left) {
stack.push(node.left)
helperStack.push(StringBuilder(path)) // LIFO
}
}
}
return result
}
private fun StringBuilder.appendChar(num: Int) {
if (length == 0) {
append("$num")
} else {
append("->$num")
}
}
}
注:
法2代码来源:(侵删)
作者:pengxurui
链接:https://leetcode-cn.com/problems/binary-tree-paths/solution/kotlin-di-gui-dfs-bfs-by-pengxurui/
来源:力扣(LeetCode)
法3
使用广度优先搜索,对于每个节点,如果有孩子节点,依次将对应的孩子节点拼接到对应的路径上。
def treepath(root):
paths = []
if not root:
return paths
node_queue = collections.deque([root])
path_queue = collections.deque([str(root.val)])
while node_queue:
#node和path的最后一个节点相同
node = node_queue.popleft()
path = path_queue.popleft()
if not node.left and not node.right:
paths.append(path)
else:
if node.left:
node_queue.append(node.left)
path_queue.append(path + '->' + str(node.left.val))
if node.right:
node_queue.append(node.right)
path_queue.append(path + '->' + str(node.right.val))
return paths