Estructura de datos y algoritmo (3) - Lista enlazada y algoritmos relacionados

Conceptos básicos de la lista enlazada

Introducción

Una lista enlazada es una estructura de almacenamiento no secuencial y no secuencial en una unidad de almacenamiento físico, y el orden lógico de los elementos de datos se realiza a través del orden de enlace de los punteros en la lista enlazada.

La lista vinculada se compone de una serie de nodos (cada elemento de la lista vinculada se denomina nodo), y los nodos se pueden generar dinámicamente en tiempo de ejecución. Cada nodo consta de dos partes: una es un campo de datos que almacena elementos de datos y la otra es un puntero que almacena la dirección del siguiente nodo.

La complejidad temporal de la inserción y eliminación de la lista enlazada es O(1), mientras que la complejidad temporal del acceso aleatorio es O(n).

lista enlazada simple

Como se muestra en la imagen ( la imagen proviene de la columna "La belleza de la estructura de datos y el algoritmo" de Geek Time )

inserte la descripción de la imagen aquí

Lista doblemente enlazada

Como se muestra en la imagen (la imagen proviene de la columna "La belleza de la estructura de datos y el algoritmo" de Geek Time)

inserte la descripción de la imagen aquí

lista enlazada circular

Como se muestra en la imagen (la imagen proviene de la columna "La belleza de la estructura de datos y el algoritmo" de Geek Time)

inserte la descripción de la imagen aquí

lista doblemente enlazada

Como se muestra en la imagen (la imagen proviene de la columna "La belleza de la estructura de datos y el algoritmo" de Geek Time)

inserte la descripción de la imagen aquí

Ideas de algoritmos comunes

puntero centinela

Ejemplo 1: Preguntas de algoritmo en "Oferta de Jianzhi" Eliminar nodos duplicados en la lista vinculada

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头
指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

Los algoritmos relacionados con listas enlazadas son generalmente relativamente simples, pero prestan atención a las condiciones de contorno. Tomando como ejemplo el ejemplo 1, cabe señalar los posibles casos especiales:

  1. El encabezado de la lista enlazada se repite: 1->1->1->1->2 será 2 después del procesamiento
  2. La lista enlazada se repite: 1->1->1->1->1 será nulo después del procesamiento

Como se muestra en la figura, agregue un nodo centinela, independientemente del caso 1 o el caso 2, nextel resultado se obtiene a través del puntero del nodo centinela.
inserte la descripción de la imagen aquí

el código se muestra a continuación

/*
 public class ListNode {
    int val;
    ListNode next = null;
 
    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    
    
    public ListNode deleteDuplication(ListNode pHead)
    {
    
    
       if(pHead == null)return null;
       ListNode root = new ListNode(-1);//充当哨兵结点
       root.next = pHead;
       ListNode preNode = root;
       ListNode nowNode = root.next;
       while(nowNode != null&&nowNode.next != null){
    
    
           ListNode nextNode = nowNode.next;
           if(nextNode.val == nowNode.val){
    
    
               while(nextNode != null&&nextNode.val == nowNode.val){
    
    
                   nextNode = nextNode.next;
               }
               preNode.next = nextNode;
               nowNode = nextNode;
           }else{
    
    
               preNode.next = nowNode;
               preNode = preNode.next;
               nowNode = nowNode.next;
           }
       }
       return root.next;
    }
}

puntero de velocidad

La idea de punteros rápidos y lentos es muy común en los algoritmos relacionados con listas enlazadas, su idea es usar los punteros rápidos y lentos para recorrer la lista enlazada y completar las operaciones que necesitamos.

Ejemplo 2: use punteros rápidos y lentos para encontrar los nodos intermedios de la lista enlazada

给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。

Suponga que la longitud de la lista enlazada es n, la velocidad del puntero rápido es 2/vez y la velocidad del puntero lento es 1/vez. Entonces, las matemáticas de la escuela primaria pueden saber que cuando el puntero rápido llega al final de la lista enlazada, el puntero lento llega al punto medio de la lista enlazada. Si aún no lo entiende, puede asumir que n = 10 o 9 y otros datos para verificar.

el código se muestra a continuación

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public ListNode middleNode(ListNode list) {
    
    
            if (list == null)return null;
            ListNode fast = list;
            ListNode slow = list;
            while (fast != null){
    
    
                fast = fast.next;
                if (fast == null)break;
                fast = fast.next;
                slow = slow.next;
            }
            return slow;
    }
}

Ejemplo 3: use punteros rápidos y lentos para encontrar el nodo de entrada del anillo en la lista enlazada

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

Hay dos pasos para resolver este problema de algoritmo:

El primer paso: determinar si hay un anillo

inserte la descripción de la imagen aquí

La velocidad del puntero rápido es 2/vez, y la velocidad del puntero lento es 1/vez. Parten al mismo tiempo del punto A. Si hay un anillo en la lista enlazada, los punteros rápido y lento deben encontrarse en el punto C (el punto C es cualquier nodo del anillo), si no hay anillo, el nodo rápido es nulo. el código se muestra a continuación:

        ListNode fast=pHead;
        ListNode low=pHead;
        while(fast!=null&&fast.next!=null){
    
    
            fast=fast.next.next;
            low=low.next;
            if(fast==low)
                break;
        }
        if(fast==null)//判断是否存在环
            return null;

Paso 2: busque el nodo de entrada del anillo en la lista vinculada

inserte la descripción de la imagen aquí

Al reunirse:

El camino recorrido por el nodo rápido es:AB + k*(BC+CB) + BC,(其中 k >= 1,k为整数)

El camino recorrido por el nodo lento es:AB + BC

Dado que los punteros rápidos son dos veces más rápidos que los nodos lentos, entonces 2*(AB + BC) = AB + K*(BC+CB) + BC, es decir AB = (k-1)(BC+CB) + CB, . Como k-1 >= 0, los dos punteros parten del punto A y del punto C respectivamente, y deben encontrarse en el punto B.

El código completo es el siguiente

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    
    
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
    
    
        ListNode fast=pHead;
        ListNode low=pHead;
        while(fast!=null&&fast.next!=null){
    
    
            fast=fast.next.next;
            low=low.next;
            if(fast==low)
                break;
        }
        if(fast==null||fast.next==null)//判断是否存在环
            return null;
        low=pHead;
        while(fast!=low){
    
    
            fast=fast.next;
            low=low.next;
        }
        return low;
    }
}

Implementación de código que debe dominarse

  • Realice una lista enlazada individualmente, una lista enlazada circular, una lista doblemente enlazada, admita operaciones de adición y eliminación
  • Implementar inversión de lista enlazada única
  • Combinar dos listas vinculadas ordenadas en una lista vinculada ordenada
  • Realizar el nodo intermedio de la lista enlazada
  • Detección de anillos en lista enlazada
  • Eliminar el último nodo n de la lista enlazada

Preguntas algorítmicas relacionadas con listas enlazadas que a menudo se prueban en entrevistas

referencia

  • codigo lelet
  • Niuke.com
  • "Oferta de puntero de espada"
  • Columna "La belleza de la estructura de datos y el algoritmo" de Geek Time

Supongo que te gusta

Origin blog.csdn.net/lichukuan/article/details/127063354
Recomendado
Clasificación