Structures de données et algorithmes pour les listes triées

                                              liste chaînée triée

                                                                  RéférenceLeetcode-148

1. Fusionner la liste liée de tri

1. Méthode 1 : tri par fusion de haut en bas

    Procédez comme suit:

  • Trouvez le milieu de la liste chaînée et divisez la liste chaînée en deux sous-listes chaînées ;

  • Fusionner et trier les deux sous-listes ;

  • Répétez les deux premières étapes pour les deux sous-listes ;

    La référence du code est la suivante :

#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 complexité temporelle de l'algorithme ci-dessus est O(n logn), et la complexité spatiale est O(logn), où n est la longueur de la liste chaînée.

2. Méthode 2 : Tri par fusion ascendant

    La méthode spécifique est la suivante :

  • Divisez la liste liée en listes sous-liées d'une longueur de subLength et fusionnez toutes les deux listes sous-liées ;

  • La longueur de subLength passe à [1, 2, 4, ...], chaque tour est le double du tour précédent, répétez les étapes ci-dessus ;

    L'exemple de code est le suivant :

#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;
}

    Le processus de tri est illustré dans la figure ci-dessous :

premier tour:

deuxième tour:

Troisième tour :

    Sa complexité temporelle est O(n logn) et sa complexité spatiale est O(1), où n est la longueur de la liste chaînée.

Je suppose que tu aimes

Origine blog.csdn.net/hu853712064/article/details/130543423
conseillé
Classement