leetcode 148. 排序链表 中等

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表

示例 1:

复制代码
输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:

复制代码
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

复制代码
输入:head = []
输出:[]

分析:

方法一:将链表的所有元素存放在数组中进行排序,再将排好序的数值依次放到链表里。

cpp 复制代码
//方法一
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
int cmp(const void *a,const void *b)
{
    int *aa=(int*)a;
    int *bb=(int*)b;
    return *aa-*bb;
}

struct ListNode* sortList(struct ListNode* head) {
    if(head==NULL)return NULL;
    struct ListNode *p=head;
    int num[50010]={0},t=0;
    while(p!=NULL)
        num[t++]=p->val,p=p->next;
    
    qsort(num,t,sizeof(int),cmp);
    p=head;
    int l=0;
    while(p!=NULL)
        p->val=num[l++],p=p->next;
    return head;
}

方法二:快速排序。

找到链表中的最大值和最小值,以它们的平均数mid作为分界值,小于等于mid的放到链表h1,大于mid的放到链表h2,之后再把h2挂在h1的后面即可。

cpp 复制代码
//方法二 快速排序
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* sortList(struct ListNode* head) {
    if(head==NULL)return NULL;
    if(head->next==NULL)return head;

    struct ListNode *prehead=(struct ListNode*)malloc(sizeof(struct ListNode));
    prehead->next=head;
    struct ListNode *h1=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode *h2=(struct ListNode*)malloc(sizeof(struct ListNode));
    h1->next=h2->next=NULL;
    int l=head->val,r=head->val;
    while(head->next!=NULL)
    {
        head=head->next;l=fmin(l,head->val);r=fmax(r,head->val);
    }
    if(l==r)
    {
        struct ListNode *p=prehead->next;
        free(prehead);
        free(h1);
        free(h2);
        return  p;     
    }
    int mid=(l+r)>>1;
    head=prehead->next;
    struct ListNode *p=head;
    while(head!=NULL)
    {
        p=head;
        head=head->next;
        if(p->val<=mid)p->next=h1->next,h1->next=p;
        else p->next=h2->next,h2->next=p;
    }

    h1->next=sortList(h1->next);
    h2->next=sortList(h2->next);
    p=h1;
    while(p->next!=NULL)p=p->next;
    p->next=h2->next;

    struct ListNode *ans=h1->next;
    free(prehead);
    free(h1);
    free(h2);
    return ans;
}

方法三:自顶向下归并排序。

  • 找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法,快指针每次移动 2 步,慢指针每次移动 1 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。
  • 对两个子链表分别排序。
  • 将两个排序后的子链表合并,得到完整的排序后的链表。
cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* sortList(struct ListNode* head) {
    if(head==NULL)return NULL;
    if(head->next==NULL)return head;
    struct ListNode *prehead=(struct ListNode*)malloc(sizeof(struct ListNode));
    prehead->next=head;
    struct ListNode *fast,*low;
    fast=low=prehead;
    while(fast->next!=NULL)
    {
        low=low->next;
        fast=fast->next;
        if(fast->next!=NULL)fast=fast->next;
    }
    if(fast==low)
    {
        free(prehead);
        return fast;
    }
    
    struct ListNode *h1=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode *h2=(struct ListNode*)malloc(sizeof(struct ListNode));
    h1->next=head;h2->next=low->next;low->next=NULL;
    h1->next=sortList(head);
    h2->next=sortList(h2->next);

    struct ListNode *h=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode *p,*q,*r;
    p=h1->next,q=h2->next,r=h;
    while(p!=NULL||q!=NULL)
    {
        if(p==NULL&&q!=NULL)r->next=q,q=q->next;
        else if(p!=NULL&&q==NULL)r->next=p,p=p->next;
        else if(p->val<q->val)r->next=p,p=p->next;
        else r->next=q,q=q->next;
        r=r->next;
    }
    //r->next=NULL;
    p=h->next;

    free(h1);
    free(h2);
    free(h);
    return p;
}

方法四:自底向上归并排序

具体做法如下。

  • 用 subLength 表示每次需要排序的子链表的长度,初始时 subLength=1。
  • 每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于 subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。
  • 将 subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于 length,整个链表排序完毕。
cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
//方法四 这里我把调试的部分也留下了
struct ListNode* sortList(struct ListNode* head) {
    if(head==NULL)return NULL;
    if(head->next==NULL)return head;

    struct ListNode *prehead=(struct ListNode*)malloc(sizeof(struct ListNode));
    prehead->next=head;

    int l=0,t=0;
    struct ListNode *p=head,*q=prehead;
    while(p!=NULL)l++,p=p->next;
    p=prehead->next;
    for(int i=1;i<l;i=fmin(i*2,l))
    {
        p=prehead->next;t=0;
        struct ListNode *index;
        while(p!=NULL)
        {
            int l1=0,l2=0;
            struct ListNode *p1,*q1,*p2,*q2;
            p1=p;
            while(p!=NULL&&l1<i)l1++,q1=p,p=p->next;
            q1->next=NULL;
            if(p==NULL)break;

            p2=p;
            while(p!=NULL&&l2<i)l2++,q2=p,p=p->next;
            q2->next=NULL;
/*
            printf("i=%d l=%d\n",i,l);
            struct ListNode *test=p1;
            printf("p1=");
            while(test!=NULL)printf("%d ",test->val),test=test->next;
            printf("\n");
            test=p2;
            printf("p2=",i);
            while(test!=NULL)printf("%d ",test->val),test=test->next;
            printf("\n");
*/
            struct ListNode *h=(struct ListNode*)malloc(sizeof(struct ListNode));
            struct ListNode *r=h;
            while(p1!=NULL||p2!=NULL)
            {
                if(p1==NULL&&p2!=NULL)r->next=p2,p2=p2->next;
                else if(p1!=NULL&&p2==NULL)r->next=p1,p1=p1->next;
                else if(p1->val<p2->val)r->next=p1,p1=p1->next;
                else r->next=p2,p2=p2->next;
                r=r->next;
            }
            if(t==0)prehead->next=h->next,t++,index=r;
            else index->next=h->next,index=r;;
            r->next=p;
/*
            test=h->next;
            printf("test=");
            while(test!=NULL)printf("%d ",test->val),test=test->next;
            printf("\n");
*/
            free(h);
/*
            printf("r=%d\n",r->val);
            test=p;
            printf("p=",i);
            while(test!=NULL)printf("%d ",test->val),test=test->next;
            printf("\n");

            test=prehead->next;
            printf("prehead=",i);
            while(test!=NULL)printf("%d ",test->val),test=test->next;
            printf("\n");
*/
        }
    }
    q=prehead->next;
    free(prehead);
    return q;
}

方法三、方法四来源:

作者:力扣官方题解

链接:https://leetcode.cn/problems/sort-list/solutions/492301/pai-xu-lian-biao-by-leetcode-solution/

相关推荐
我是聪明的懒大王懒洋洋23 分钟前
力扣力扣力:53.最大子数组和
算法·leetcode·职场和发展
九圣残炎38 分钟前
【从零开始的LeetCode-算法】3345. 最小可整除数位乘积 I
java·算法·leetcode
林开落L3 小时前
前缀和算法习题篇(上)
c++·算法·leetcode
九圣残炎4 小时前
【从零开始的LeetCode-算法】2559. 统计范围内的元音字符串数
java·算法·leetcode
韭菜盖饭5 小时前
LeetCode每日一题3261---统计满足 K 约束的子字符串数量 II
数据结构·算法·leetcode
xxxmmc5 小时前
Leetcode 75 Sort colors
leetcode·三指针移动问题
geng小球5 小时前
LeetCode 78-子集Ⅱ
java·算法·leetcode
拒绝头秃从我做起5 小时前
9.回文数-力扣(LeetCode)
leetcode
AnFany5 小时前
LeetCode【0028】找出字符串中第一个匹配项的下标
python·算法·leetcode·字符串·kmp·字符串匹配
__AtYou__7 小时前
Golang | Leetcode Golang题解之第563题二叉树的坡度
leetcode·golang·题解