Listas vinculadas y recursividad
La respuesta al problema de eliminar elementos de listas vinculadas
Descripción del problema: elimine el elemento con valor 6 en la lista vinculada [1, 2, 6, 3, 4, 5, 6]
-
ListNode.java
Descripción de la estructurapublic class ListNode { int val; ListNode next; ListNode(int x) { val = x;} /** * 链表节点构造函数,自定义 * @param arr */ ListNode(int[] arr) { if (arr == null || arr.length == 0) { throw new IllegalArgumentException("arr can not be empty"); } this.val = arr[0]; ListNode cur = this; for (int i = 1; i < arr.length; i++) { cur.next = new ListNode(arr[i]); cur = cur.next; } } @Override public String toString() { StringBuilder sb = new StringBuilder(); ListNode cur = this; while (cur != null) { sb.append(cur.val).append(" -> "); cur = cur.next; } sb.append("NULL"); return sb.toString(); } }
-
De forma convencional, las tres partes [cabeza, centro y cola] de la lista enlazada se procesan por separado
public ListNode removeElement(ListNode head, int val) { // 链表头部节点删除 while (head != null && head.val == val) head = head.next; // 链表尾部节点删除 if (head == null) { return null; } // 链表中间部分节点删除 ListNode prev = head; while (prev.next != null) { if (prev.next.val == val) prev.next = prev.next.next; else prev = prev.next; } return head; } }
-
El método del nodo principal virtual hace que cada nodo de la lista vinculada contenga un prenodo, mejorando el código
public ListNode removeElement(ListNode head, int val) { // 建立虚拟头结点,保证链表中每一个节点前面均有节点 ListNode dummyHead = new ListNode(-1); dummyHead.next = head; // 链表节点删除 ListNode prev = dummyHead; while (prev.next != null) { if (prev.next.val == val) prev.next = prev.next.next; else prev = prev.next; } return dummyHead.next; }
-
¡hazte una prueba!
public static void main(String[] args) { int[] arr = { 1, 2, 6, 3, 4, 5, 6}; ListNode res = new ListNode(arr); System.out.println(res); new Solution2().removeElement(res, 6); System.out.println(res); } ------------------------------------------ 1 -> 2 -> 6 -> 3 -> 4 -> 5 -> 6 -> NULL 1 -> 2 -> 3 -> 4 -> 5 -> NULL
Recursión: un mecanismo lógico de componentes muy importante en las computadoras
-
Esencialmente, el problema original se transforma en un mismo problema más pequeño, como la suma de matrices.
SUM(arr[0...n-1]) = arr[0] + SUM(arr[1...n-1])
SUM(arr[1...n-1]) = arr[1] + SUM(arr[2...n-1])
SUM(arr[n-1...n-1]) = arr[n-1] + SUM(arr[]) = arr[n-1] + 0
-
La composición del algoritmo recursivo
求解最基本的问题
把原问题转化成更小的问题
-
Las listas vinculadas son recursivas
- La lista enlazada puede entenderse como un cuerpo de conexión de varios nodos y también puede considerarse como
一个节点和一个链表
un cuerpo de conexión. - También es
NULL
la lista vinculada más básica. - ¡Para facilitar la comprensión, hice un dibujo!
- ¡De acuerdo con la imagen, podemos reescribir el código!
public ListNode removeElementNew(ListNode head, int val) { // 基础问题 one if (head == null) { return null; } // 处理子链表,分解问题 two head.next = removeElementNew(head.next, val); // 处理结果,若当前返回子链表满足条件,便跳过节点 three return head.val == val ? head.next : head; }
- Por ejemplo, ahora hay una lista vinculada
1, 2, 3
y quiero eliminar un elemento.2
¿Cómo se realiza el método anterior?step1
Ingrese [1, 2, 3] una lista vinculada con 1 como nodo principalone
cabeza! = nulotwo
head.next = ?, ingrese la primera recursividad,step2
step2
Ingrese [2, 3] una lista vinculada con 2 como nodo principalone
cabeza! = nulotwo
head.next = ?, ingrese la segunda recursividad,step3
step3
Entrada [3] Lista vinculada con 3 como nodo principalone
cabeza! = nulotwo
head.next = ?, ingrese la tercera recursión,step4
step4
Parámetro de entrada [NULL], lista vinculada NULLone
head == null , returnnull
, ¡ ha surgido el problema básico! ! !
step5
De regresostep3 two
two
head.next = 【null】three
head.val == 2? head.next: cabeza- return head , ahora la lista vinculada es [3], return
step2 two
step6
De regresostep2 two
two
head.next = 【3】three
head.val == 2? head.next: head ,此时条件满足,为true
- return head.next , ahora la lista vinculada es [3], return
step1 two
step7
De regresostep1 two
two
head.next = 【3】three
head.val == 2? head.next: cabeza- retorno de la cabeza , esta vez la lista es [1, 3], de nuevo
step1
, se ha llevado sobreone
,,two
,three
el método devuelve, extremos.
- La lista enlazada puede entenderse como un cuerpo de conexión de varios nodos y también puede considerarse como
-
Las llamadas recursivas tienen un costo: llamada de función + espacio de pila del sistema (registrando la posición de ejecución actual, el estado de la variable y el consumo de tiempo). Si no se resuelve el problema básico, es decir, no hay una salida recursiva, la ejecución del método ocupar memoria hasta que la memoria esté llena o se desborde, provocando que el sistema se sobrecargue. Un algoritmo siempre debe finalizar después de un número limitado de ejecuciones, y cada paso se puede completar en un tiempo limitado.