如何对一个无序单链表排序

        对一个单向的无序链表进行排序,通常可以采用以下几种排序算法:插入排序、归并排序、快速排序等。对于链表来说,归并排序是一个特别适合的选择,因为它是一个稳定的排序算法,不需要额外的空间,并且具有较好的时间复杂度。链表的节点在排序时可以直接调整指针,因此比数组更适合使用归并排序。

归并排序的思路:
1. 分割:将链表从中间分成两个部分。
2. 递归排序:递归地对每个部分进行排序。
3. 合并:将两个已排序的子链表合并成一个有序链表。

步骤:
1. 使用快慢指针找到链表的中点,并将链表分成两部分。
2. 递归排序这两部分链表。
3. 合并两个已排序的链表。
 

#include 
using namespace std;

// 定义单链表节点
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

// 合并两个有序链表
ListNode* merge(ListNode* l1, ListNode* l2) {
    // 创建一个虚拟头结点
    ListNode* dummy = new ListNode(0);
    ListNode* current = dummy;

    // 合并两个链表
    while (l1 != nullptr && l2 != nullptr) {
        if (l1->val < l2->val) {
            current->next = l1;
            l1 = l1->next;
        } else {
            current->next = l2;
            l2 = l2->next;
        }
        current = current->next;
    }

    // 如果有剩余的节点,直接连接
    if (l1 != nullptr) {
        current->next = l1;
    } else if (l2 != nullptr) {
        current->next = l2;
    }

    return dummy->next;
}

// 寻找链表的中点
ListNode* findMiddle(ListNode* head) {
    if (head == nullptr) return nullptr;
    
    ListNode* slow = head;
    ListNode* fast = head;
    
    while (fast != nullptr && fast->next != nullptr) {
        slow = slow->next;
        fast = fast->next->next;
    }

    return slow;
}

// 归并排序
ListNode* mergeSort(ListNode* head) {
    if (head == nullptr || head->next == nullptr) {
        return head; // 如果链表为空或只有一个元素,返回本身
    }

    // 寻找中点并分割链表
    ListNode* middle = findMiddle(head);
    ListNode* secondHalf = middle->next;
    middle->next = nullptr; // 断开链表

    // 递归排序两个子链表
    ListNode* left = mergeSort(head);
    ListNode* right = mergeSort(secondHalf);

    // 合并两个已排序的链表
    return merge(left, right);
}

// 用于打印链表
void printList(ListNode* head) {
    ListNode* current = head;
    while (current != nullptr) {
        cout << current->val << " -> ";
        current = current->next;
    }
    cout << "null" << endl;
}

// 主函数,测试代码
int main() {
    // 构造链表
    ListNode* head = new ListNode(4);
    head->next = new ListNode(2);
    head->next->next = new ListNode(1);
    head->next->next->next = new ListNode(3);

    cout << "Original list: ";
    printList(head);

    // 排序链表
    head = mergeSort(head);

    cout << "Sorted list: ";
    printList(head);

    return 0;
}

 详细解释:

        1. ListNode 结构体:定义了链表节点,包含一个整数值 `val` 和一个指向下一个节点的指针 `next`。  
        2. merge 函数:负责合并两个已排序的链表。通过比较两个链表的节点值,逐个将较小的节点加入到新的链表中,直到其中一个链表为空,最后将另一个链表剩余的部分接到合并链表的末尾。

        3. findMiddle 函数:使用快慢指针找到链表的中点。快指针每次走两步,慢指针每次走一步。当快指针到达末尾时,慢指针刚好到达链表的中点。

        4. mergeSort 函数:递归实现归并排序。首先找到链表的中点,然后递归地对左右两个子链表进行排序,最后将两个已排序的子链表合并。

        5. printList 函数:用于打印链表,方便查看排序前后的结果。

复杂度分析:
        时间复杂度:每次递归都将链表分为两半,递归深度为 `O(log n)`,在每一层递归中合并链表的时间是 `O(n)`,因此总的时间复杂度为 `O(n log n)`。
        空间复杂度:归并排序需要递归栈的空间,递归的最大深度为 `O(log n)`,因此空间复杂度为 `O(log n)`。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值