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 = []
输出:[]

提示:

链表中节点的数目在范围 [0, 5 * 104] 内
-105 <= Node.val <= 105

进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

自解

自解大失败,拼尽全力无法战胜超时

//按顺序排到新链表里,超时
struct ListNode dummy;
struct ListNode * s_insert(struct ListNode *newnode)
{
    struct ListNode *temp=NULL,*next=NULL,*head=&dummy;
    if(head->next==NULL)
    {
        dummy.next=newnode;
        next=newnode->next;
        newnode->next=NULL;
        return next;
    }
    
    while(head->next!=NULL&&head->next->val<newnode->val)
    {
        head=head->next;
    }
    temp=head->next;
    head->next=newnode;
    next=newnode->next;
    newnode->next=temp;
    return next;
}

struct ListNode* sortList(struct ListNode* head) {
    dummy.next=NULL;
    while(head!=NULL)
    {
        head=s_insert(head);
    }
    return dummy.next; 
}
 //双指针冒泡排序,超时,实质是对两两交换链表中的节点题加上了判断条件
struct ListNode* sortList(struct ListNode* head) {
    if(head==NULL)return head;
    struct ListNode dummy;
    dummy.next=head;
    head=&dummy;
    struct ListNode *right=&dummy,*p=NULL;
    struct ListNode *temp=NULL,*temp1=NULL;
    while(head->next->next!=p)
    {
        while(right->next->next!=p)
        {
            if(right->next->val>right->next->next->val)
            {
                temp=right->next->next->next;
                right->next->next->next=right->next;
                temp1=right->next->next;
                right->next->next=temp;
                right->next=temp1;
            }
            right=right->next;
        }
        p=right->next;
        right=head;
    }
    return dummy.next;

}

力扣解

1.递归
将链表拆成一个个节点再合并

// 876. 链表的中间结点(快慢指针)
struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode* pre = head;
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while (fast && fast->next) {
        pre = slow; // 记录 slow 的前一个节点
        slow = slow->next;
        fast = fast->next->next;
    }
    pre->next = NULL; // 断开 slow 的前一个节点和 slow 的连接
    return slow;
}

// 21. 合并两个有序链表(双指针)
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    struct ListNode dummy; // 用哨兵节点简化代码逻辑
    struct ListNode* cur = &dummy; // cur 指向新链表的末尾
    while (list1 && list2) {
        if (list1->val < list2->val) {
            cur->next = list1; // 把 list1 加到新链表中
            list1 = list1->next;
        } else { // 注:相等的情况加哪个节点都是可以的
            cur->next = list2; // 把 list2 加到新链表中
            list2 = list2->next;
        }
        cur = cur->next;
    }
    cur->next = list1 ? list1 : list2; // 拼接剩余链表
    return dummy.next;
}

struct ListNode* sortList(struct ListNode* head) {
    // 如果链表为空或者只有一个节点,无需排序
    if (head == NULL || head->next == NULL) {
        return head;
    }
    // 找到中间节点 head2,并断开 head2 与其前一个节点的连接
    // 比如 head=[4,2,1,3],那么 middleNode 调用结束后 head=[4,2] head2=[1,3]
    struct ListNode* head2 = middleNode(head);
    // 分治
    head = sortList(head);
    head2 = sortList(head2);
    // 合并
    return mergeTwoLists(head, head2);
}

作者:灵茶山艾府
链接:https://leetcode.cn/problems/sort-list/solutions/2993518/liang-chong-fang-fa-fen-zhi-die-dai-mo-k-caei/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

仿解

看过答案自己写的递归,非常惭愧,合并有序链表明明已经做出来,却又做错,找了好一会错误
image

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *MiddleFind(struct ListNode *head)//找中间节点
{
    struct ListNode *fast=head,*slow=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
    }
    return slow;
}

struct ListNode *hebing(struct ListNode *list1,struct ListNode *list2)//合并有序节点
{
	struct ListNode dummy,*p=&dummy;
	while(list1&&list2)
	{
		if(list1->val<=list2->val)
		{
			p->next=list1;
			p=p->next; 
			list1=list1->next;
		}
		else
		{
			p->next=list2;
			p=p->next; 
			list2=list2->next;
		}
	}
	p->next=list1?list1:list2;
	return dummy.next;

}

struct ListNode* sortList(struct ListNode* head) {
    struct ListNode *temp=NULL,*temp1=NULL;
    if(head==NULL||head->next==NULL)//链表不可切割时停止递归直接返回
    {
        return head;
    }
    else
    {
        temp=MiddleFind(head);//找中间节点
        if(temp->next==NULL)//考虑只剩两个节点的特殊情况,此时中间节点是最后一个节点
        {
            temp1=temp;
            head->next=NULL;
        }
        else 
        {
            temp1=temp->next;
            temp->next=NULL;
        }
    }
        head=sortList(head);//递归,此时不需要判断是否为单节点链表,参考上方的返回条件,单节点链表会直接返回自身并且不进行递归
        temp1=sortList(temp1);//递归


    return hebing(head,temp1);;
}
posted @ 2025-04-29 11:35  Osen  阅读(20)  评论(0)    收藏  举报