Estructuras de datos y algoritmos para listas ordenadas

                                              lista enlazada ordenada

                                                                  ReferenciaLeetcode-148

1. Fusionar lista enlazada de clasificación

1. Método 1: clasificación de combinación de arriba hacia abajo

    Proceder de la siguiente:

  • Encuentre el punto medio de la lista vinculada y divida la lista vinculada en dos listas subvinculadas;

  • Combinar y ordenar las dos sublistas;

  • Repita los dos primeros pasos para las dos sublistas;

    La referencia del código es la siguiente:

#include <iostream>
using namespace std;

struct ListNode {
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        return sortList(head, nullptr);
    }

    ListNode* sortList(ListNode* head, ListNode* tail) {
        if (head == nullptr) { // 为空结点返回
            return head;
        }
        if (head->next == tail) { // 只剩一个结点后返回
            head->next = nullptr;
            return head;
        }
        /* 双指针法找到中间结点 */
        ListNode* slow = head, *fast = head;
        while (fast != tail) {
            slow = slow->next;
            fast = fast->next;
            if (fast != tail) {
                fast = fast->next;
            }
        }
        ListNode* mid = slow;
        /* 合并两个子链表 */
        return merge(sortList(head, mid), sortList(mid, tail));
    }

    /* 合并两个子链表的方法 */
    ListNode* merge(ListNode* head1, ListNode* head2) {
        ListNode* dummyHead = new ListNode(0);
        ListNode* temp = dummyHead, *temp1 = head1, *temp2 = head2;
        while (temp1 != nullptr && temp2 != nullptr) {
            if (temp1->val <= temp2->val) {
                temp->next = temp1;
                temp1 = temp1->next;
            } else {
                temp->next = temp2;
                temp2 = temp2->next;
            }
            temp = temp->next;
        }
        if (temp1 != nullptr) {
            temp->next = temp1;
        } else if (temp2 != nullptr) {
            temp->next = temp2;
        }
        return dummyHead->next;
    }
};

int main() {
    Solution sol;
    ListNode *l1 = new ListNode(-1);
    ListNode *l2 = new ListNode(5);
    ListNode *l3 = new ListNode(3);
    ListNode *l4 = new ListNode(4);
    ListNode *l5 = new ListNode(0);

    l1->next = l2;
    l2->next = l3;
    l3->next = l4;
    l4->next = l5;

    sol.sortList(l1);

    return 0;
}

    La complejidad temporal del algoritmo anterior es O(n logn), y la complejidad espacial es O(logn), donde n es la longitud de la lista enlazada.

2. Método 2: ordenación de combinación de abajo hacia arriba

    El método específico es el siguiente:

  • Divida la lista vinculada en listas subvinculadas con una longitud de subLength y combine cada dos listas subvinculadas;

  • La longitud de subLength cambia a [1, 2, 4, ...], cada ronda es el doble de la ronda anterior, repita los pasos anteriores;

    El ejemplo de código es el siguiente:

#include <iostream>
using namespace std;

struct ListNode {
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (head == nullptr) {
            return head;
        }
        /* 计算链表的长度 */
        int length = 0;
        ListNode* node = head;
        while (node != nullptr) {
            length++;
            node = node->next;
        }

        ListNode* dummyHead = new ListNode(0, head);
        for (int subLength = 1; subLength < length; subLength <<= 1) { // subLength左移1位,相当于subLength*2
            ListNode* prev = dummyHead, *curr = dummyHead->next;
            while (curr != nullptr) {
                ListNode* head1 = curr;
                for (int i = 1; i < subLength && curr->next != nullptr; i++) { // 根据subLength来更新curr,以此获得head2的位置
                    curr = curr->next;
                }
                ListNode* head2 = curr->next;
                curr->next = nullptr; // 断开链表,形成head1子链表
                curr = head2;
                for (int i = 1; i < subLength && curr != nullptr && curr->next != nullptr; i++) { // 同上
                    curr = curr->next;
                }
                ListNode* next = nullptr;
                if (curr != nullptr) { // 获取next指针,并且断开链表,形成head2子链表
                    next = curr->next;
                    curr->next = nullptr;
                }
                ListNode* merged = merge(head1, head2); // 合并两个子链表
                prev->next = merged;
                /* 更新prev、next指针 */
                while (prev->next != nullptr) {

                    prev = prev->next;
                }
                curr = next;
            }
        }
        return dummyHead->next;
    }

    /* 合并两个有序链表 */
    ListNode* merge(ListNode* head1, ListNode* head2) {
        ListNode* dummyHead = new ListNode(0);
        ListNode* temp = dummyHead, *temp1 = head1, *temp2 = head2;
        while (temp1 != nullptr && temp2 != nullptr) {
            if (temp1->val <= temp2->val) {
                temp->next = temp1;
                temp1 = temp1->next;
            } else {
                temp->next = temp2;
                temp2 = temp2->next;
            }
            temp = temp->next;
        }
        if (temp1 != nullptr) {
            temp->next = temp1;
        } else if (temp2 != nullptr) {
            temp->next = temp2;
        }
        return dummyHead->next;
    }
};

int main() {
    Solution sol;
    ListNode *l1 = new ListNode(-1);
    ListNode *l2 = new ListNode(5);
    ListNode *l3 = new ListNode(3);
    ListNode *l4 = new ListNode(4);
    ListNode *l5 = new ListNode(0);

    l1->next = l2;
    l2->next = l3;
    l3->next = l4;
    l4->next = l5;

    return 0;
}

    El proceso de clasificación se muestra en la siguiente figura:

primera ronda:

Segunda ronda:

Tercera ronda:

    Su complejidad temporal es O(n logn) y su complejidad espacial es O(1), donde n es la longitud de la lista enlazada.

Supongo que te gusta

Origin blog.csdn.net/hu853712064/article/details/130543423
Recomendado
Clasificación