深度解析 589. N 叉树的前序遍历:递归、非递归,通用非递归全掌握
2023-10-13 20:50:06
## 前言
589. N 叉树的前序遍历 是 LeetCode 上的一道简单难度算法题,考察了树的遍历算法的应用。给定一个 N 叉树,要求以先序遍历的方式输出其节点值。先序遍历是一种深度优先搜索算法,它以递归或非递归的方式沿着树的每个节点深度遍历,先访问根节点,然后访问其所有子节点。
## 递归方法
递归是解决树遍历问题的一种常见方法。以下是使用递归实现 N 叉树的前序遍历的 Python 代码:
def preorder(root):
"""
Perform preorder traversal on an N-ary tree.
Parameters:
root: The root node of the N-ary tree.
Returns:
A list of the values of the nodes in the N-ary tree, in preorder.
"""
if not root:
return []
result = [root.val] # Add the value of the root node to the result.
# Recursively perform preorder traversal on each child of the root node.
for child in root.children:
result += preorder(child)
return result
在代码中,preorder()
函数接受一个 N 叉树的根节点作为参数,并返回一个包含 N 叉树中节点值的有序列表。函数首先检查根节点是否为空,如果是,则直接返回一个空列表。然后,它将根节点的值添加到结果列表中。接着,函数递归地对根节点的每个子节点调用 preorder()
函数,并将每个子节点遍历的结果添加到结果列表中。最后,函数返回结果列表。
## 非递归方法
除了递归方法之外,还可以使用非递归的方式来实现 N 叉树的前序遍历。以下是非递归版本的 Python 代码:
def preorder_non_recursive(root):
"""
Perform preorder traversal on an N-ary tree non-recursively.
Parameters:
root: The root node of the N-ary tree.
Returns:
A list of the values of the nodes in the N-ary tree, in preorder.
"""
if not root:
return []
result = [] # Initialize the result list.
stack = [root] # Initialize the stack with the root node.
# While the stack is not empty, pop the top node from the stack and add its value to the result list.
# Then, push all of its children onto the stack.
while stack:
node = stack.pop()
result.append(node.val)
for child in node.children[::-1]:
stack.append(child)
return result
在代码中,preorder_non_recursive()
函数也接受一个 N 叉树的根节点作为参数,并返回一个包含 N 叉树中节点值的有序列表。函数首先检查根节点是否为空,如果是,则直接返回一个空列表。然后,它将根节点推入堆栈中。接着,函数从堆栈中弹出栈顶节点,并将它的值添加到结果列表中。然后,函数将该节点的所有子节点反向推入堆栈中。函数重复这个过程,直到堆栈为空。最后,函数返回结果列表。
## 通用非递归方法
以上两种方法都只适用于 N 叉树。但是,我们可以使用一种通用的非递归方法来遍历任意类型的树,包括二叉树、三叉树和多叉树。这种方法被称为 Morris 遍历 。Morris 遍历不需要使用额外的空间来存储节点,并且它的时间复杂度与递归方法相同。
以下是用 Python 实现的 Morris 遍历的代码:
def morris_traversal(root):
"""
Perform preorder traversal on a tree using the Morris traversal algorithm.
Parameters:
root: The root node of the tree.
Returns:
A list of the values of the nodes in the tree, in preorder.
"""
if not root:
return []
result = [] # Initialize the result list.
current = root # Initialize the current node to the root node.
# While the current node is not None, loop through the following steps:
while current:
# If the current node has no left child, add its value to the result list and move to its right child.
if not current.left:
result.append(current.val)
current = current.right
# Otherwise, find the rightmost node in the current node's left subtree and make it point to the current node.
else:
predecessor = current.left
while predecessor.right and predecessor.right != current:
predecessor = predecessor.right
# If the right child of the predecessor is None, make it point to the current node and move to the current node's left child.
if not predecessor.right:
predecessor.right = current
current = current.left
# Otherwise, reset the right child of the predecessor to None and add the current node's value to the result list.
else:
predecessor.right = None
result.append(current.val)
current = current.right
return result
在代码中,morris_traversal()
函数接受一个树的根节点作为参数,并返回一个包含树中节点值的有序列表。函数首先检查根节点是否为空,如果是,则直接返回一个空列表。然后,它将根节点设为当前节点。接着,函数进入一个循环,在循环中,它根据当前节点的情况执行以下操作:
- 如果当前节点没有左子节点,则将它的值添加到结果列表中,然后移动到它的右子节点。
- 否则,找到当前节点的左子树中最右边的节点,并让它指向当前节点。
- 如果最右边的节点的右子节点为空,则让它指向当前节点,然后移动到当前节点的左子节点。
- 否则,将最右边的节点的右子节点设为空,将当前节点的值添加到结果列表中,然后移动到当前节点的右子节点。
函数重复这个过程,直到当前节点为空。最后,函数返回结果列表。
## 结论
- N 叉树的前序遍历是 LeetCode 上的一道简单难度算法题,考察了树的遍历算法的应用。这篇文章介绍了三种遍历 N 叉树的方法:递归、非递归和通用非递归。通过这些方法,我们可以对 N 叉树进行深度优先搜索,并输出其节点值的有序列表。