链表的排序(插入、快排、自底向下的归并排序)

题目

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

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

链表的插入排序法

   //插入排序法,非进阶
    public ListNode sortList(ListNode head) {
    
        if(head == null || head.next == null){
            return head;
        }
        ListNode cur = head;
        ListNode nextNode = head.next;
        ListNode aux = new ListNode(-1);
        aux.next = head;
        while(nextNode != null){
            //只要下一个节点大于当前的就讲当前节点和下一个节点的指针向后移动
            if(nextNode.val > cur.val){
                cur = cur.next;
                nextNode = cur.next;
            }else{
                //将下一个节点从链表中“摘取”下来,因为下一个节点小于当前节点,
                //所以要将“摘取”下来的节点放到当前节点之前的合适位置。
                cur.next = nextNode.next;
                ListNode node1 = aux;
                ListNode node2 = aux.next;
                while(nextNode.val > node2.val){
                    node1 = node2;
                    node2 = node2.next;
                }
                //找到了合适的位置
                node1.next = nextNode;
                nextNode.next = node2;
                //设置新的下个节点
                nextNode = cur.next;
            }
        }
        return aux.next;
    }

链表的快速排序

    public ListNode quickSort(ListNode start,ListNode end){
            if(start == null || end == null || start == end){
                return start;
            }
            ListNode first = start;
            ListNode second = start.next;
            int value = start.val;
            while(second != end.next && second != null){             
                if(second.val < value){
                    first = first.next;
                  //可以应对链表形式如5->3->6->0这种情况,保证大于value的没有排序的节点往后放 
                    if(first != second){
                        int temp = first.val;
                        first.val = second.val;
                        second.val =temp;
                    }
                }
                second = second.next;
            }
            //比如最开始节点是整个链表的最小值,这时候就不用移动指针
            if(start != first){
                int temp = start.val;
                start.val = first.val;
                first.val = temp;
            }
            quickSort(start,first);
            quickSort(first.next,end);
            return start;
        }

写快排我记三个例子,第一个例子是最开始的节点就是全链表的最小节点;第二个例子最开始额节点是全链表最大的节点;第三个例子是5->3->6->0这个例子。

自底向下的归并排序

使用自底向上的方法实现归并排序,则可以达到 O(1)O(1) 的空间复杂度。
首先求得链表的长度 \textit{length}length,然后将链表拆分成子链表进行合并。

在这里插入图片描述
官方的方法:

  //自底向下的归并排序,进阶
    public ListNode sortList(ListNode head) {

        if(head == null){
            return head;
        }
        int length = 0;
        ListNode node = head;
        while(node != null){
            length++;
            node = node.next;
        }
        ListNode resultHead = new ListNode(0,head);
        for(int subLength = 1;subLength < length; subLength <<= 1){
            ListNode pre = resultHead, cur = resultHead.next;
            while(cur != null){
                ListNode head1 = cur;
                for(int i = 1; i < subLength && cur.next != null; i++){
                    cur = cur.next;
                }
                ListNode head2 = cur.next;
                cur.next = null;
                cur = head2;
                for(int i = 1; i < subLength && cur != null && cur.next != null; i++){
                    cur = cur.next;
                }
                ListNode temp = null;
                if(cur != null){
                    temp = cur.next;
                    cur.next = null;
                }
                ListNode merged = merge(head1,head2);
                pre.next = merged;
                while(pre.next != null){
                    pre = pre.next;
                }
                cur = temp;
            }
        }
        return resultHead.next;      
    }
    public ListNode merge(ListNode h1,ListNode h2){
        ListNode mergerHead = new ListNode(0);
        ListNode h = mergerHead;
        ListNode head1 = h1,head2 = h2;
        while(head1 != null && head2 != null){
            if(head1.val < head2.val){
                h.next = head1;
                head1 = head1.next;
            }else{
                h.next = head2;
                head2 = head2.next;
            }
            h = h.next;
        }
        if(head1 != null){
            h.next = head1;
        }else if(head2 != null){
            h.next = head2;
        }
        return mergerHead.next;
    }

注意一下左移赋值就行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值