[LeetCode专题] 148. 排序链表 使用方法:暴力解法+快速排序+归并排序 全网最详细

148. 排序链表
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
示例:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
一、暴力解法
Colletions的2个静态排序方法:
排序:sort(list) sort(list,comparator)
最大最小值:max(list) min(list)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        ListNode cur=head;
        List<Integer> list=new ArrayList<>();
        while(cur!=null)
        {
            list.add(cur.val);
            cur=cur.next;
        }
        Collections.sort(list);
        cur=head;
        for(Integer x:list)
        {
            cur.val=x;
            cur=cur.next;
        }
        return head;
    }
}

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

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        return head==null?null:mergeSort(head);//空指针判断
    }
    public ListNode mergeSort(ListNode head)
    {
        if(head.next==null)//防止单个指针
        {
            return head;
        }
        //快慢指针
        ListNode fast=head;//快慢指针,并且标记一个慢指针
        ListNode slow=head;
        ListNode prev=slow;
        while(fast!=null && fast.next!=null)
        {
            prev=slow;
            fast=fast.next.next;
            slow=slow.next;
        }
        prev.next=null;//一分为二
        ListNode left=mergeSort(head);
        ListNode right=mergeSort(slow);
        return merge(left,right);
    }
    ListNode merge(ListNode l,ListNode r)//这个其实就是我们之前的合并两个有序链表,虽然他是无序的,道理都是一样的,不懂的可以看我的这个博客:https://blog.csdn.net/qq_42956868/article/details/122199463?spm=1001.2014.3001.5501
    {
        ListNode dummyHead=new ListNode(0);
        ListNode cur=dummyHead;
        while(l!=null && r!=null)
        {
            if(l.val<=r.val){
                cur.next=l;
                cur=cur.next;
                l=l.next;
            }
            else{
                cur.next=r;
                cur=cur.next;
                r=r.next;
            }
        }
        if(l!=null)
        {
            cur.next=l;
        }
        if(r!=null)
        {
            cur.next=r;
        }
        return dummyHead.next;
    }
}

方法二:快速排序
快速排序的实质:
1.选定Pivot中心轴
2.将大于Pivot的数字放在Pivot的右边
3.将小于Pivot的数字放在Pivot的左边
4.分别对左右子序列重复前三步操作

所以在编写代码之前我也忘记快排的定义,然后B站看看视频了解了下概念,下面是编写的代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
    if(head==null || head.next==null) return head;//这里是单数据或者空数据的时候,直接返回数据
    
    ListNode dummyHead=new ListNode();//定义虚拟指针
    dummyHead.next=head;//连接头结点

    return quickSort(dummyHead,null);//使用快排

    }
    public ListNode quickSort(ListNode head,ListNode end)
    {
        if(head==end || head.next==end || head.next.next==end){
            return head;
        }//快排判断如果虚拟头结点以及连接头结点或者单目标情况,直接返回数据
        ListNode temp=new ListNode();//临时虚拟变量
        ListNode partition=head.next;//分割线,重点
        ListNode position=partition;//位置指针
        ListNode tmp=temp;//临时虚拟变量的指针
        while(position.next!=end)//判断位置指针是否已经跳过末尾元素
        {
            if(position.next.val<partition.val)//临时虚拟变量指针存储小与分割线的数据
            {
                tmp.next=position.next;
                tmp=tmp.next;
                position.next=position.next.next;
            }else{
                position=position.next;
            }
        }
        tmp.next=head.next;//连接较大的数据
        head.next=temp.next;//头结点更新
        quickSort(head,partition);//左边快排
        quickSort(partition,end);//右边快排
        return head.next;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值