当前位置:   article > 正文

leetcode 148题 排序链表JAVA实现_148链表排序 java

148链表排序 java

leetcode刷了9题了,一直没有在博客上面记录一下,发现做完一题忘了一题所以今天开始做一道记一道。
链表排序

使用递归的归并排序

首先这个方法肯定不满足题目要求的常数级空间复杂度,但是还是从这里入手,因为算法太渣了。。。。

链表的排序要比数组排序难,主要是链表的断链还有重新建立连接。递归需要的时间复杂度为递归的深度为logn
递归排序的思想很简单,先把递归的把左面和右面排好序然后在merge
归并排序
代码分为两个部分

  1. cut部分
    先用fast和slow双指针法找到链表的中点(奇数链表为中点,偶数链表为中点的左面一个)
    灵魂画图。。。。。。。。双指针法找中点
    然后进行断链操作,把两个链表进行递归操作
    在这里插入图片描述
    递归结束条件 : 一个节点
    在这里插入图片描述
  2. merge部分
    双指针法插入链表
    新建一个临时的头结点用于构造新链表然后定义一个H指针指向新链表的最后一个结点,接下来比较P1和P2哪个小就把哪个接上就好了,最后把剩余加到尾巴处就可以了
//链表排序 要求nlogn
public class leetcode148 {
    public static class ListNode{
        public int val;
        public ListNode next;
        public ListNode( int val){
            this.val = val;
        }
    }
    //排序cut部分
    public static ListNode mergeSort(ListNode head){
        if(head==null||head.next==null){
            return head;
        }
        ListNode slow = head;
        ListNode quick = head.next;
        while(quick!=null&&quick.next!=null){
            slow = slow.next;
            quick = quick.next.next;
        }
        ListNode tmp = slow.next;
        slow.next = null;
//        printList(head);
//        printList(tmp);
        head = mergeSort(head);
        tmp = mergeSort(tmp);

        return merge(head,tmp);
    }
//合并部分
    private static ListNode merge(ListNode head, ListNode tmp) {
        ListNode p1 = head;
        ListNode p2 = tmp;
        ListNode tempH = new ListNode(0);
        ListNode h = tempH;

        while(p1!=null&&p2!=null){
            if(p1.val<p2.val){
                h.next = p1;
                h = p1;
                p1=p1.next;
            }else{
                h.next = p2;
                h = p2;
                p2=p2.next;
            }
        }
        if(p1!=null){
            h.next = p1;
        }
        if(p2!=null){
            h.next = p2;
        }
//        printList(tempH.next);
        return tempH.next;
    }
//打印链表
    public static void printList(ListNode head){
        ListNode p = head;
        while(p!=null){
            System.out.print(p.val+"->");
            p=p.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        ListNode a = new ListNode(9);
        a.next= new ListNode(1);
        a.next.next  = new ListNode(7);
        a.next.next.next = new ListNode(3);
        a.next.next.next.next  = new ListNode(5);
        a.next.next.next.next.next = new ListNode(2);
        printList(a);
        ListNode head = mergeSort(a);
        printList(head);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

链表排序

从底到顶直接排序(非归并排序)

如果要求空间复杂度为O(1)的话就不能用递归来排序了,只能用迭代的方式
先1个1个合并然后2个2个合并,结束条件为合并的个数大于等于链表长度
bottomtoup排序
代码主要是控制两个循环

size循环
  1. 控制合并的个数size增长,每轮合并size长度的链表。
  2. size=1 每次循环乘以2 当size<=length时一直继续循环
合并
  1. tail指针开始指向dummyhead,cur指向第一个节点
  2. left指针指向左面的链表,right指向右面的链表
  3. 通过cut操作可以实现断链并返回链表后面的部分,cur指向后面的部分在这里插入图片描述
  4. 然后merge操作是双路归并,返回的链表可以用tail指向
  5. 最后移动tail到最后一个结点在这里插入图片描述
  6. cur==null时代表此轮归并完毕
cut操作

cut操作可以将链表截断前n长度并返回后面的部分

容易出现的错

cut操作可能size大小比链表长度要大,所以要在循环里判断一下
在这里插入图片描述
dummyhead的用处:
每轮cur都从新指向头结点,所以定义一个虚拟的头结点,这样很方便就能找到新的结点(开始代码写错了,写的是cur=head,但是head已经被排在后面了)
因为头结点会变化,定义一个虚拟的头结点代替头结点的指针。
在这里插入图片描述

/*merge 和 数据结构 在上面有*/
//不用递归的归并排序
    public static ListNode mergeSort2(ListNode head){
        if(head==null||head.next==null){
            return head;
        }
        //先求链表的长度
        int length = 0;
        ListNode p = head;
        while(p!=null){
            p=p.next;
            length++;
        }

        ListNode dummyHead = new ListNode(Integer.MIN_VALUE);
        dummyHead.next = head;

        //迭代控制每次合并的size大小
        for(int size=1;size<=length;size <<=1){
            //不能用head头结点 head头结点已经变化到末尾了
            ListNode cur = dummyHead.next;
            ListNode tail = dummyHead;
            //按size大小合并一轮
            while(cur!=null){
                ListNode left = cur;
                ListNode right = cut(left,size);
                cur = cut(right,size);

                tail.next = merge(left,right);
                //tail指针指向最后一个结点可以连接merge完的链表

                while(tail.next!=null){
                    tail=tail.next;
                }
            }
            //printList(dummyHead.next);
        }
        return dummyHead.next;
    }
    //切断链表的n个结点 然后返回剩余部分的head
    public static ListNode cut(ListNode head,int size){
        if(head==null){
            return null;
        }
        ListNode cur = head;
        while(--size!=0&&cur.next!=null){
            cur = cur.next;
        }
        ListNode p = cur.next;
        cur.next = null;
        return p;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/488939?site
推荐阅读
相关标签
  

闽ICP备14008679号