单链表的排序(C++)

问题描述

给定一个节点数为n的无序单链表,对其按升序排序。

数据范围:0<n≤1000000<n≤100000,保证节点权值在[−109,109][−109,109]之内。

要求:空间复杂度 O(n)O(n),时间复杂度 O(nlogn)O(nlogn)

示例1

输入:

复制代码
[1,3,2,4,5]

返回值:

复制代码
{1,2,3,4,5}

示例2

输入:

复制代码
[-1,0,-2]

返回值:

复制代码
{-2,-1,0}

解题思路

首先,Merge 函数用于合并两个已排序的链表,采用逐个节点比较的方式,将较小的节点接到结果链表中,最终返回合并后的链表头。sortInList 函数通过快慢指针拆分链表,将链表分成两部分,递归地对每部分进行排序。拆分的过程是:慢指针 left 指向链表的头节点,快指针 rightmid 找到链表的中点,将链表分成两半,然后对每半部分递归排序,最后通过 Merge 合并两个有序链表。

代码实现

cpp 复制代码
    ListNode* Merge(ListNode* head1, ListNode* head2)
    {
        if(head1 == nullptr) return head2;
        if(head2 == nullptr) return head1;

        auto ret = new ListNode(-1);
        auto head = ret;
        while (head1 && head2) {
            if (head1->val < head2->val) {
                ret->next = head1;
                head1 = head1->next;
            }
            else {
                ret->next = head2;
                head2 = head2->next;
            }
            ret = ret->next;
        }
        if (head1) {
            ret->next = head1;
        }
        if (head2) {
            ret->next = head2;
        }
        return head->next;
    } 
    ListNode* sortInList(ListNode* head) {
        // write code here
        if (head == nullptr || head->next == nullptr)
        {
            return head;
        }
        ListNode* left = head, *mid = head->next, *right = head->next;
        while (right && right->next) {
            left = left->next;
            mid = mid->next;
            right = right->next->next;
        }
        left->next = nullptr;
        return Merge(sortInList(head), sortInList(mid));
    }

代码解析

  1. 归并排序

如果链表为空或只有一个节点,直接返回链表;通过快慢指针将链表拆分成两部分,递归地对每部分进行排序,然后使用 Merge 合并排序后的子链表,最终返回排序后的链表。

cpp 复制代码
    ListNode* sortInList(ListNode* head) {
        // write code here
        if (head == nullptr || head->next == nullptr)
        {
            return head;
        }
        ListNode* left = head, *mid = head->next, *right = head->next;
        while (right && right->next) {
            left = left->next;
            mid = mid->next;
            right = right->next->next;
        }
        left->next = nullptr;
        return Merge(sortInList(head), sortInList(mid));
    }
  1. 合并两个已排序的链表

如果其中一个链表为空,直接返回另一个链表;否则,创建虚拟头节点 ret,逐个比较两个链表的节点,将较小的节点连接到结果链表。最后将剩余的部分连接到结果链表,返回合并后的链表。

cpp 复制代码
    ListNode* Merge(ListNode* head1, ListNode* head2)
    {
        if(head1 == nullptr) return head2;
        if(head2 == nullptr) return head1;

        auto ret = new ListNode(-1);
        auto head = ret;
        while (head1 && head2) {
            if (head1->val < head2->val) {
                ret->next = head1;
                head1 = head1->next;
            }
            else {
                ret->next = head2;
                head2 = head2->next;
            }
            ret = ret->next;
        }
        if (head1) {
            ret->next = head1;
        }
        if (head2) {
            ret->next = head2;
        }
        return head->next;
    } 

总结

本文介绍了如何使用归并排序对链表进行排序。首先通过 Merge 函数合并两个有序链表,再通过 sortInList 函数递归地拆分链表并排序。归并排序的优势在于其稳定性和 O(nlog⁡n)O(n \log n) 的时间复杂度,尤其适合链表结构的排序,因为它不需要额外的数组空间。通过快慢指针的拆分和递归合并,最终实现了一个高效的链表排序算法。

相关推荐
超爱笑嘻嘻2 分钟前
shared_ptr八股收集 C++
c++
我想进大厂21 分钟前
图论---朴素Prim(稠密图)
数据结构·c++·算法·图论
我想进大厂26 分钟前
图论---Bellman-Ford算法
数据结构·c++·算法·图论
AIGC大时代28 分钟前
高效使用DeepSeek对“情境+ 对象 +问题“型课题进行开题!
数据库·人工智能·算法·aigc·智能写作·deepseek
光而不耀@lgy32 分钟前
C++初登门槛
linux·开发语言·网络·c++·后端
lkbhua莱克瓦2436 分钟前
用C语言实现——一个中缀表达式的计算器。支持用户输入和动画演示过程。
c语言·开发语言·数据结构·链表·学习方法·交友·计算器
啊丢_42 分钟前
C++——Lambda表达式
开发语言·c++
CODE_RabbitV1 小时前
【深度强化学习 DRL 快速实践】近端策略优化 (PPO)
算法
Wendy_robot2 小时前
【滑动窗口+哈希表/数组记录】Leetcode 438. 找到字符串中所有字母异位词
c++·算法·leetcode
程序员-King.2 小时前
day49—双指针+贪心—验证回文串(LeetCode-680)
算法·leetcode·贪心算法·双指针