Listas vinculadas e recursão
A resposta para o problema de exclusão de elementos de lista vinculada
Descrição do problema: Exclua o elemento com valor 6 na lista vinculada [1, 2, 6, 3, 4, 5, 6]
-
ListNode.java
Descrição da estruturapublic 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(); } }
-
Na forma convencional, as três partes [cabeça, meio e cauda] da lista encadeada são processadas separadamente
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; } }
-
O método do nó principal virtual faz com que cada nó da lista vinculada contenha um pré-nó, melhorando o 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; }
-
faça um teste!
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
Recursão: um mecanismo lógico de componente muito importante em computadores
-
Essencialmente, o problema original é transformado em um mesmo problema menor, como a soma de matrizes!
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
-
A composição do algoritmo recursivo
求解最基本的问题
把原问题转化成更小的问题
-
Listas vinculadas são recursivas
- A lista vinculada pode ser entendida como um corpo de conexão de vários nós e também pode ser considerada
一个节点和一个链表
um corpo de conexão. - É
NULL
também a lista vinculada mais básica. - Para facilitar o entendimento, fiz um desenho!
- De acordo com a foto, podemos reescrever o 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 exemplo, agora existe uma lista vinculada
1, 2, 3
e desejo excluir um elemento.Como2
o método acima é executado?step1
Insira [1, 2, 3] uma lista vinculada com 1 como o nó principalone
head! = nulltwo
head.next = ?, insira a primeira recursão,step2
step2
Insira [2, 3] uma lista vinculada com 2 como o nó principalone
head! = nulltwo
head.next = ?, insira a segunda recursão,step3
step3
Entrada [3] Lista vinculada com 3 como o nó principalone
head! = nulltwo
head.next = ?, insira a terceira recursão,step4
step4
Parâmetro de entrada [NULL], lista vinculada NULLone
head == null , returnnull
, o problema básico surgiu! ! !
step5
De volta astep3 two
two
head.next = 【null】three
head.val == 2? head.next: head- return head , agora a lista encadeada é [3], return
step2 two
step6
De volta astep2 two
two
head.next = 【3】three
head.val == 2? head.next: head ,此时条件满足,为true
- retornar head.next , agora a lista vinculada é [3], retornar
step1 two
step7
De volta astep1 two
two
head.next = 【3】three
head.val == 2? head.next: head- retorno cabeça , desta vez, a lista é [1, 3], de volta
step1
, foi realizada ao longoone
,,two
,three
o método retorna, extremidades.
- A lista vinculada pode ser entendida como um corpo de conexão de vários nós e também pode ser considerada
-
Chamadas recursivas têm um custo: chamada de função + espaço de pilha do sistema (registrando a posição de execução atual, status da variável e consumo de tempo). Se o problema básico não for tratado, ou seja, não houver saída recursiva, a execução do método será ocupar a memória até que ela esteja cheia ou transborde, Fazendo com que o sistema acabe. Um algoritmo deve sempre terminar após um número limitado de execuções e cada etapa pode ser concluída em um tempo limitado.