Recorrido en orden del árbol binario de Leetcode: Python implementa tres soluciones

0 descripción del tema

Enlace al título original de Leetcode: recorrido en orden del árbol binario
Inserte la descripción de la imagen aquí

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

1 algoritmo recursivo

Ideas y algoritmos En
primer lugar, debemos comprender cuál es el recorrido en orden de un árbol binario: atravesar este árbol en la forma de visitar el subárbol izquierdo-raíz nodo-subárbol derecho, y cuando visitemos el subárbol izquierdo o el subárbol derecho, seguimos Recorra de la misma manera hasta atravesar el árbol completo. Por lo tanto, todo el proceso transversal es naturalmente recursivo y podemos simular directamente este proceso con una función recursiva.
La definición inorder (root) representa la respuesta actualmente atravesada al nodo raíz, luego, de acuerdo con la definición, solo necesitamos llamar de forma recursiva a inorder (root.left) para atravesar el subárbol izquierdo del nodo raíz, luego agregar el valor del nodo raíz a la respuesta, y luego llamar de forma recursiva a inorder (root.right) Para atravesar el subárbol derecho del nodo raíz, la condición para la terminación recursiva es encontrar un nodo vacío.

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right)

Complejidad del algoritmo Complejidad del
tiempo: O (n) O (n)O ( n ) , dondennn es el número de nodos de árbol binario. En el recorrido del árbol binario, cada nodo será visitado una vez y solo una vez.
Complejidad espacial:O (n) O (n)O ( n ) . La complejidad del espacio depende de la profundidad de la pila recursiva, y la profundidad de la pila puede alcanzarO (n) O (n)cuando el árbol binario es una cadenaNivel O ( n ) .

2 algoritmo iterativo (pila)

También podemos implementar funciones recursivas de manera iterativa. Los dos métodos son equivalentes. La diferencia es que una pila se mantiene implícitamente durante la recursividad, y necesitamos simular explícitamente esta pila cuando se itera.

# 其核心思想如下:
# 使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
# 如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
# 如果遇到的节点为灰色,则将节点的值输出。
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        White, Gray = 0, 1
        res = []
        stack = [(White,root)]
        while stack:
            color, node = stack.pop()
            if not node: continue
            if color == White:
                stack.append((White,node.right))
                stack.append((Gray,node))
                stack.append((White,node.left))
            else:
                res.append(node.val)
        return res

Complejidad del algoritmo Complejidad del
tiempo: O (n) O (n)O ( n ) , dondennn es el número de nodos de árbol binario. En el recorrido del árbol binario, cada nodo será visitado una vez y solo una vez.
Complejidad espacial:O (n) O (n)O ( n ) . La complejidad del espacio depende de la profundidad de la pila recursiva, y la profundidad de la pila puede alcanzarO (n) O (n)cuando el árbol binario es una cadenaNivel O ( n ) .

3 recorrido en orden de Morris

Ideas y algoritmos
El algoritmo transversal de Morris es otro método para atravesar árboles binarios, que puede reducir la complejidad espacial del recorrido no recursivo en orden a O (1).
El recorrido de Morris es un método de recorrido de espacio constante, su esencia es un árbol binario enhebrado (árbol binario enhebrado), en esencia, en realidad usa n + 1 punteros a NULL en el árbol binario.
En el proceso de recorrido, el recorrido de Morris utiliza el puntero derecho vacío del nodo hoja para apuntar al nodo sucesor del recorrido en orden, evitando así la dependencia de la pila.Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

# (1)对于一个节点cur,找到它左子树的最右节点,看这个节点的right指针是null还是指向cur。
# (2)如果是null,说明左子树还没处理过,更新该指针为cur,然后进入左子树继续上述流程。
# (3)如果该指针已经是cur了,说明左子树已经处理完毕,现在是处理完毕后顺这最右节点的right指针回到该cur节点的,需先将该right指针恢复为null,处理该cur节点后进入右子树重复流程⑴。
class Solution:
    def inorderTraversal(self, root: TreeNode) -> list:
        node, res = root, []
        while node:
            if not node.left:
                res.append(node.val)
                node = node.right
            else:
                pre = node.left
                while pre.right and pre.right != node:
                    pre = pre.right
                if not pre.right:
                    pre.right = node
                    node = node.left
                else:
                    pre.right = None
                    res.append(node.val)
                    node = node.right
        return res

Complejidad del algoritmo Complejidad del
tiempo: O (n) O (n)O ( n ) , dondennn es el número de nodos en el árbol de búsqueda binaria. En el recorrido de Morris, cada nodo se visitará dos veces, por lo que la complejidad del tiempo total esO (2 n) O (2n)O ( 2 n ) =O (n) O (n)O ( n ) .
Complejidad espacial:O (1) O (1)O ( 1 )

referencia

Notación de color: un método general y conciso de recorrido de árbol recorrido de
Morris

Supongo que te gusta

Origin blog.csdn.net/OuDiShenmiss/article/details/109197755
Recomendado
Clasificación