Resumen de problemas de algoritmos clásicos relacionados con la lista enlazada (lenguaje C + estructura de datos)

Explicaremos algunos de los problemas algorítmicos más clásicos en listas enlazadas:

1. Encuentra el nodo común de dos listas enlazadas.

2. Determine si la lista enlazada tiene un ciclo.

3. Dada una lista enlazada, determine si hay un anillo, si hay un primer nodo que vuelve al anillo y ningún retorno está vacío (Versión mejorada sobre la segunda pregunta).

4. Dada una lista enlazada, cada nodo contiene un puntero aleatorio adicional que puede apuntar a cualquier nodo de la lista enlazada o a un nodo vacío. Solicitudes para devolver una copia profunda de esta lista vinculada.

5. Clasificación por inserción en la lista enlazada.

6. En una lista vinculada ordenada, si hay nodos duplicados, elimine los nodos duplicados en la lista vinculada, los nodos duplicados no se conservan y se devuelve el puntero al encabezado de la lista vinculada.

1. Explicación detallada

1. Encuentra el nodo común de las dos listas enlazadas (como se muestra en la figura).

typedef struct ListNode node;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    node* cur1=headA;
    node* cur2=headB;
    int sum1=0;
    int sum2=0;
    int before=0;
    while(cur1->next){//判断第一个节点的长度,并走到最后一个节点
        cur1=cur1->next;
        sum1++;
    }
    while(cur2->next){//判断第二个节点的长度,并走到最后一个节点
        cur2=cur2->next;
        sum2++;
    }
    if(cur1!=cur2){//判断最后一个节点是否相等,相等则有公共节点,不相等则没有直接返回.
        return NULL;
    }
    if(sum1>sum2){//判断两个链表那个长,长的那个先走,直到两个距离最后一个节点相同距离.
        before=sum1-sum2;
        for(int i=0;i<before;i++){
            headA=headA->next;
        }
    }
    if(sum2>sum1){//同上
        before=sum2-sum1;
        for(int i=0;i<before;i++){
            headB=headB->next;
        }
    }
    while(headA!=headB){//两个同时向后走当其相等时,这个节点就是公共节点.
        headA=headA->next;
        headB=headB->next;
    }
    return headA;
}

2. Determine si la lista enlazada tiene un ciclo (como se muestra en la figura).

typedef struct ListNode node;
bool hasCycle(struct ListNode *head) {
    if(NULL==head || NULL==head->next){//判空
        return false;
    }
    node* slow=head;//定义两个快慢指针
    node* fast=head;
    int temp=0;
    while(1){//快指针每次走两步,慢指针每次走一步.
        slow=slow->next;
        fast=fast->next->next;
        if(NULL==fast || NULL==fast->next){//如果可以走到尾部说明无环.
            temp=1;
            break;
        }
        if(slow==fast){//如果快慢指针相遇说明有环.
            break;
        }
    }
    if(1==temp){
        return false;
    }else{
        return true;
    }
}

3. Dada una lista enlazada, determine si hay un anillo, hay un primer nodo que vuelve al anillo y ningún retorno está vacío (versión mejorada de la segunda pregunta) (como se muestra en la figura).

typedef struct ListNode node;
struct ListNode *detectCycle(struct ListNode *head) {
   node* slow=head;
   node* fast=head;
   int temp=0;
   while(fast!=NULL && fast->next!=NULL){//同上,定义快慢指针判断是否有环.
       slow=slow->next;
       fast=fast->next->next;
       if(slow==fast){
           temp=1;
           break;
       }
   } 
   if(0==temp){//temp为0说明没环,直接返回.
       return NULL;
   }
   node* head2=fast;
   while(head2 != head){//有环同时向后走,相遇时便是入环点.
       head=head->next;
       head2=head2->next;
   }
   return head2;
}

4. Dada una lista enlazada, cada nodo contiene un puntero aleatorio adicional que puede apuntar a cualquier nodo de la lista enlazada o a un nodo vacío. Solicitudes para devolver una copia profunda de esta lista vinculada.

https://blog.csdn.net/weixin_49312527/article/details/121598778?spm=1001.2014.3001.5501

5. Clasificación por inserción en la lista enlazada.

a. Defina un nuevo nodo vacío, conecte el primero en la lista vinculada directamente a este nodo vacío y luego compare los nodos posteriores con los nodos detrás del nuevo nodo, retroceda si es más grande que él y continúe con compare, if go Al final, está directamente conectado al último nodo. Si es más pequeño que él, está directamente conectado al frente. Después de que se completan todas las conexiones, el siguiente devuelto al nuevo nodo es el nodo principal. del nodo insertado.

typedef struct ListNode Node;
struct ListNode* insertionSortList(struct ListNode* head){
    if(NULL==head||NULL==head->next){//判空
        return head;
    }   
    Node* no_head=(Node*)malloc(sizeof(Node));
    no_head->next=head;
    Node* cur=head->next;
    head->next=NULL;
    Node* Next=NULL;
    Node* new_head=NULL;
    while(cur!=NULL){//定义一个新的空节点,将链表中的第一个直接连到这个空节点上,然后后面的
//节点依次与新节点后面的节点比较,比其大就向后走,继续比较,如果走到最后则直接连到最后一个节点
//上,如果比其小则直接连到其前面.等到全部连完,返回新节点的next就是插入排序后的节点的头节点.
        Next=cur->next;
        cur->next=NULL;
        new_head=no_head;
        while(new_head->next!=NULL){
            if(new_head->next->val<cur->val){
                new_head=new_head->next;
            }else{
                break;
            }
        }
        cur->next=new_head->next;
        new_head->next=cur;
        cur=Next;
    }
    return no_head->next;
}

6. En una lista vinculada ordenada, si hay nodos duplicados, elimine los nodos duplicados en la lista vinculada, los nodos duplicados no se conservan y se devuelve el puntero al encabezado de la lista vinculada.

a. Primero defina un nodo de cabeza vacío conectado al frente de la lista enlazada, deje que prv esté en no_head (nodo de cabeza vacío), cur en cabeza (nodo de origen), si el nodo cur no es un nodo de cola y es igual al nodo detrás de él, simplemente ingrese el ciclo y siga retrocediendo, encuentre el nodo desigual para finalizar el ciclo, prv está directamente conectado aquí, omita el nodo igual, cur continúa colocándose en el siguiente de prv, y se juzga el ciclo. cur no es igual al siguiente, prv y cur retroceden al mismo tiempo para continuar con el ciclo de juicio.

typedef struct ListNode Node;
struct ListNode* deleteDuplication(struct ListNode* pHead ) {
    if(NULL==pHead  || NULL==pHead->next){
        return pHead;
    }
    Node* no_head=(Node*)malloc(sizeof(Node));
    no_head->next=pHead;
    Node* prev=no_head;
    Node* cur=pHead;
//首先定义一个空的头节点连接在该链表前,让prv处在no_head(空的头节点),cur处在head(源头节点),
//如果cur节点不是尾节点,并
//且与其后面的节点相等,就进入循环一直向后走,找到不相等的节点是结束循环,prv直接连在这,跳过所的
//相等节点,cur继续放在prv的next处,进行循环判断.如果cur与其后面的不相等,prv和cur同时向后走继续
//循环判断.
    while(NULL!=cur){
        if(cur->next!=NULL && cur->val==cur->next->val){
            while(cur->next!=NULL && cur->val==cur->next->val){
                cur=cur->next;
            }
            prev->next=cur->next;
            cur=cur->next;
        }else{
            prev=prev->next;
            cur=cur->next;
        }
    }
    return no_head->next;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_49312527/article/details/121892690
Recomendado
Clasificación