Un artículo aclara el recorrido del orden anterior, medio y posterior del árbol binario desde la recursividad hasta el bucle, ¡así que no tiene que preocuparse por prepararse para la entrevista!

La temporada de reclutamiento de otoño está llegando nuevamente. Ya sea que se trate de una prueba escrita o una entrevista con programación de pizarra, el recorrido del árbol binario es una pregunta de calentamiento muy común, y el método de escritura recursiva debe ser familiar para los estudiantes. Pero el entrevistador ve que usted está tan familiarizado con su escritura. El joven tiene huesos exquisitos y es un buen material para pandear. Debe estudiarlo con cuidado, y surge la siguiente pregunta. ¿Cuáles son las limitaciones de pasar? blablabla... Bueno, tienes un buen punto, reescribámoslo con un bucle. ¿este? ...Muchos estudiantes se quedaron atascados. El artículo de hoy es para resolver este problema, explicando el problema a fondo a la vez.

Sobre la pila

Antes que nada, repasemos qué es una pila El principio de una pila es primero en entrar, último en salir. El primer elemento en entrar es siempre el último en salir, y el último elemento en entrar es siempre el primero en salir. Muchos de nuestros comportamientos en la vida real usan la pila. Pongamos un ejemplo práctico: digamos que estás comiendo

  1. Descubrí que mi tarea no estaba terminada, así que comencé a escribir mi tarea. Pila de tareas: [comer]
  2. A la mitad de mi tarea, tenía sed y fui a beber agua. Pila de tareas: [comida, tarea]
  3. Vi un gatito en camino a beber agua, así que fui a acariciarlo. Pila de tareas: [comer, tarea, beber agua]
  4. Después de acariciar al gato, continúa bebiendo agua. Pila de tareas: [comida, tarea]
  5. Después de beber el agua, comencé a hacer mi tarea. Pila de tareas: [comer]
  6. Después de terminar la tarea, comenzamos a comer. pila de tareas: []
  7. Después de la cena, ¿qué debo hacer?

Como se puede ver en el ejemplo anterior, cuando nos interrumpe una tarea en curso, ponemos la tarea en curso en la pila, sacamos la más reciente cada vez y continuamos procesando. De hecho, las llamadas a funciones recursivas también se basan en este principio. Comencemos a explicar paso a paso cómo reescribir el recorrido recursivo en un bucle.

El llamado recorrido de orden pre-medio-posterior difiere de la posición del nodo raíz:

  1. Reserva: nodo raíz - expansión transversal del subárbol izquierdo - expansión transversal del subárbol derecho
  2. En orden: expansión transversal del subárbol izquierdo - nodo raíz - expansión transversal del subárbol derecho
  3. Posorden: expansión transversal del subárbol izquierdo - expansión transversal del subárbol derecho - nodo raíz

Lo revisaremos a mano antes de comenzar a escribir el código. (x) representa el nodo con el valor x en el árbol original, y los subárboles izquierdo y derecho apuntan al mismo; x representa el nodo con el valor x, los subárboles izquierdo y derecho apuntan a nulo, que es el nodo copiado.

recorrido de pedido anticipado

  • El nodo raíz se coloca en la pila. pila: [(1)]
  • Extraiga el elemento superior 1 de la pila y agregue el valor a la matriz de resultados. Debido a que el subárbol izquierdo se procesa primero y luego se procesa el subárbol derecho, preste atención al orden de apilamiento. Resultado: [1], pila: [(3), (2)]
  • Extraiga el elemento superior 2 de la pila, agregue el valor a la matriz de resultados y luego procese el subárbol de este nodo. Resultado: [1, 2], pila: [(3), (5), (4)]
  • El elemento 4 en la parte superior de la pila se extrae, y el valor se agrega a la matriz de resultados, y el subárbol está vacío, por lo que no se inserta en la pila. Resultado: [1, 2, 4], Pila: [(3), (5)]
  • Extraiga el elemento superior 5 de la pila, agregue el valor a la matriz de resultados, el subárbol izquierdo está vacío y solo el subárbol derecho debe insertarse en la pila. Resultado: [1, 2, 4, 5], pila: [(3), (8)]
  • El elemento superior 8 de la pila se extrae, y el valor se agrega a la matriz de resultados, y el subárbol está vacío, por lo que no se inserta en la pila. Resultado: [1, 2, 4, 5, 8], pila: [(3)]
  • Extraiga el elemento superior 3 de la pila, agregue el valor a la matriz de resultados y luego procese el subárbol de este nodo. Resultado: [1, 2, 4, 5, 8, 3], pila: [(7), (6)]
  • El elemento 6 en la parte superior de la pila se extrae, y el valor se agrega a la matriz de resultados, y el subárbol está vacío, por lo que no se inserta en la pila. Resultado: [1, 2, 4, 5, 8, 3, 6], pila: [(7)]
  • El elemento 7 en la parte superior de la pila se extrae, y el valor se agrega a la matriz de resultados, y el subárbol está vacío, por lo que no se inserta en la pila. Resultado: [1, 2, 4, 5, 8, 3, 6, 7], pila: []
  • La pila está vacía, fin.

Por lo tanto, es fácil traducir los pasos anteriores en código: verifique que el código sea correcto en LintCode .

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> ret = new ArrayList<>();
    if (root != null) {
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root); // 初始化堆栈
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop(); // 弹出栈顶元素处理
            ret.add(node.val);
            if (node.right != null) {
                stack.push(node.right); // 右子树不为空先入栈,然后再判断左子树。
            }
            if (node.left != null) {
                stack.push(node.left);
            }
        }
    }
    return ret;
}

Recorrido en orden

Preste atención al recorrido en orden, primero recorra el subárbol izquierdo, luego muestre el nodo raíz y finalmente recorra el subárbol derecho. Según el sentimiento, el orden de apilamiento debe ser: subárbol derecho, nodo raíz, subárbol izquierdo. Tenga en cuenta que solo se necesita un valor cuando el nodo raíz se inserta en la pila, por lo que el nodo debe copiarse y los subárboles izquierdo y derecho deben estar vacíos. Debido a que cada elemento en la pila es un nodo, si los subárboles izquierdo y derecho no están vacíos, significa que el nodo no es un nodo hoja y no se puede generar directamente, pero los subárboles izquierdo y derecho deben procesarse primero de acuerdo con el recorrido. orden.

  • El nodo raíz se coloca en la pila. pila: [(1)]
  • Abre el elemento superior 1 de la pila, porque los subárboles izquierdo y derecho no están vacíos, de acuerdo con el orden transversal, el subárbol izquierdo se procesa primero, luego el nodo actual y luego el subárbol derecho se procesa, así que presta atención a el orden de apilamiento. Nota : debido a que solo se pueden generar los nodos cuyos subárboles izquierdo y derecho están vacíos, copie el nodo, configure los subárboles izquierdo y derecho para que estén vacíos y luego insértelos en la pila. resultado: [], pila: [(3),  1 , (2)]
  • Extraiga el elemento superior 2 de la pila y empújelo en la pila en el orden de recorrido. resultado: [], pila: [(3),  1 , (5), 2 , (4)]
  • Extraiga el elemento superior 4 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4], pila: [(3),  1 , (5), 2 ]
  • Extraiga el elemento superior 2 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4, 2], pila: [(3),  1 , (5)]
  • Extraiga el elemento superior 5 de la pila, porque el subárbol izquierdo está vacío, por lo que se genera directamente, y luego el subárbol derecho se inserta en la pila. Resultado: [4, 2, 5], pila: [(3),  1 , (8)]
  • Extraiga el elemento superior 8 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4, 2, 5, 8], pila: [(3),  1 ]
  • Extraiga el elemento superior 1 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4, 2, 5, 8, 1], pila: [(3)]
  • Extraiga el elemento superior 3 de la pila, porque los subárboles izquierdo y derecho no están vacíos, empuje la pila en el orden de recorrido. Resultado: [4, 2, 5, 8, 1], pila: [(7), 3 , (6)]
  • Extraiga el elemento superior 6 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. [4, 2, 5, 8, 1, 6], pila: [(7), 3 ]
  • Extraiga el elemento superior 3 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. [4, 2, 5, 8, 1, 6, 3], pila: [(7)]
  • Extraiga el elemento superior 7 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. [4, 2, 5, 8, 1, 6, 3, 7], pila: []
  • La pila está vacía, fin.

En resumen, los pasos para traducir a código son los siguientes:

  • El nodo raíz se inserta en la pila.
  • si la pila no está vacía
    • Pop el elemento superior de la pila
    • Si el subárbol derecho no está vacío, empújelo a la pila.
    • Determinar si el subárbol izquierdo está vacío
      • ¡Sí! Cree un nuevo nodo, copie el valor del nodo actual, configure los subárboles izquierdo y derecho para que estén vacíos, empújelos a la pila y luego empuje el subárbol izquierdo a la pila.
      • ¡No! Salida del valor actual directamente.

Verifica que el código sea correcto en LintCode .

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> ret = new ArrayList<>();
    if (root != null) {
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            if (node.right != null) {
                stack.push(node.right);
            }
            if (node.left == null) {
                ret.add(node.val);
            } else {
                TreeNode tmp = new TreeNode(node.val); // 构造函数默认左右子树为null
                stack.push(tmp);
                stack.push(node.left);
            }
        }
    }
    return ret;
}

traspaso de pedidos posteriores

Ahora que se ha realizado el recorrido en orden, el recorrido posterior se basa en el código del recorrido en orden. En pocas palabras, si los subárboles izquierdo y derecho del nodo no están todos vacíos, copie el valor del nodo actual y colóquelo en la pila, luego, si el subárbol derecho no está vacío, empújelo a la pila, y si el subárbol izquierdo el subárbol no está vacío, empújelo en la pila. Para facilitar la comprensión de todos, tomemos la molestia de escribir los pasos específicos nuevamente.

  • El nodo raíz se coloca en la pila. pila: [(1)]
  • Extraiga el elemento superior 1 de la pila, porque los subárboles izquierdo y derecho no están todos vacíos, por lo que se colocan en la pila en orden. resultado: [], pila: [ 1 , (3), (2)]
  • Extraiga el elemento superior 2 de la pila, porque los subárboles izquierdo y derecho no están todos vacíos, por lo que se colocan en la pila en orden. Resultado: [], stack: [ 1 , (3), 2 , (5), (4)] ( Nota : aquí se copia el nodo 2 y los subárboles izquierdo y derecho están todos vacíos).
  • Extraiga el elemento superior 4 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4], pila: [ 1 , (3), 2 , (5)]
  • Extraiga el elemento superior 5 de la pila, porque el subárbol derecho no está vacío, por lo que se coloca en la pila en orden. Resultado: [4], pila: [ 1 , (3), 2 , 5 , (8)]
  • Extraiga el elemento superior 8 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4, 8], pila: [ 1 , (3), 2 , 5 ]
  • Extraiga el elemento superior 5 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4, 8, 5], pila: [ 1 , (3), 2 ]
  • Extraiga el elemento superior 2 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4, 8, 5, 2], pila: [ 1 , (3)]
  • Extraiga el elemento superior 2 de la pila, porque los subárboles izquierdo y derecho no están todos vacíos, por lo que se colocan en la pila en orden. Resultado: [4, 8, 5, 2], pila: [ 1 , 3 , (7), (6)]
  • Extraiga el elemento superior 5 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4, 8, 5, 2, 6], pila: [ 1 , 3 , (7)]
  • Extraiga el elemento superior 7 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4, 8, 5, 2, 6, 7], pila: [ 1 , 3 ]
  • Extraiga el elemento superior 3 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4, 8, 5, 2, 6, 7, 3], pila: [ 1 ]
  • Extraiga el elemento superior 1 de la pila, porque los subárboles izquierdo y derecho están vacíos, por lo que se genera directamente. Resultado: [4, 8, 5, 2, 6, 7, 3, 1], pila: []
  • La pila está vacía, fin.

En resumen, los pasos para traducir a código son los siguientes:

  • El nodo raíz se inserta en la pila.
  • si la pila no está vacía
    • Pop el elemento superior de la pila
    • Determinar si los subárboles izquierdo y derecho están vacíos
      • ¡Sí! Si el subárbol derecho no está vacío, empújelo a la pila; si el subárbol izquierdo no está vacío, empújelo a la pila.
      • ¡No! Salida del valor actual directamente.

Verifica que el código sea correcto en LintCode .

public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> ret = new ArrayList<>();
    if (root != null) {
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            if ((node.left == null) && (node.right == null)) {
                ret.add(node.val);
            } else {
                TreeNode tmp = new TreeNode(node.val);
                stack.push(tmp);
                if (node.right != null) {
                    stack.push(node.right);
                }
                if (node.left != null) {
                    stack.push(node.left);
                }
            }
        }
    }
    return ret;
}

Finalmente, recomiendo una herramienta en línea para dibujar árboles binarios: http://mshang.ca/syntree/ . Ingrese la expresión usted mismo, [] representa un subárbol vacío. La estructura más simple se expresa de la siguiente manera: [1 [2] [3]]. El ejemplo en el artículo se puede generar con [1 [2 [4] [5 [] [8]]] [3 [6] [7]]].

Supongo que te gusta

Origin blog.csdn.net/panda_lin/article/details/108230003
Recomendado
Clasificación