• 算法——排序链表


    给定一个乱序的链表,要求将链表进行排序后然后返回头结点,要求时间复杂度为 O(nlogn)。
    leetcode

    1. 由于无法快速得到链表中某一节点得值,时间复杂度为 O(nlogn),所以,通过归并排序。
    2. 归并的核心思想是将数据分为两段有序的数据,再进行合并。
    3. 归并的程序设计上可以由递归和迭代两种方法,迭代稍微复杂一些,需要计算每次段的长度。递归就利用分治的思想,每次将数据分为两段。

    首先是迭代方法。

    /**
     * created by lippon
     */
    class Solution {
        public ListNode sortList(ListNode head) {
            int n = 0; 
            // 定义一个虚拟节点,因为头节点会改变,所以,通过虚拟节点来指向头节点
            // 最后返回虚拟节点的下一节点即为头节点
            ListNode dummy = new ListNode(0);
            dummy.next= head;
    
    		// 计算链表长度
            ListNode cur = head;
            while(cur != null) {
                cur = cur.next;
                n ++;
            }
    
    		// 计算每次归并的长度,由小变大
            for(int i = 1; i < n; i *= 2) {
            	// 将当前指针指向头
                cur = dummy;
                // 计算归并段的起始位置
                for(int j = 0; j + i < n; j += 2 * i){
                	// 定义前后两个节点的位置
                    int x = 0, y = 0;
                    // 定义前后两个节点
                    ListNode first = cur.next;
                    ListNode second = cur.next;
    				// 将后指针送到后半段
                    int temp = 0;
                    while(temp < i && second != null) {
                        temp ++;
                        second = second.next;
                    }
    				// 前后两个节点都没超出段的情况下,将当前指针不断指向小的节点
    				// 这里需要注意的是后节点可能会超出链表长度
                    while(x < i && y < i && second != null) {
                        if(first.val < second.val) {
                            cur.next = first;
                            first = first.next;
                            cur = cur.next;
                            x ++;
                        } else {
                            cur.next = second;
                            second = second.next;
                            cur = cur.next;
                            y ++;
                        }
                    }
    				
    				// 接上剩余的节点
                    while(x < i) {
                        cur.next = first;
                        first = first.next;
                        cur = cur.next;
                        x ++;
                    }
    
                    while(y < i && second != null) {
                        cur.next = second;
                        second = second.next;
                        cur = cur.next;
                        y ++;
                    }
    				// 将当前节点接到下一段
                    cur.next = second;
                }
            }
    
            return dummy.next;
        }
    }
    

    递归方法

    class Solution {
        public ListNode sortList(ListNode head) {
             if(head == null ||head.next == null){
                return head;
            }
    
    		// 截取中间节点
            ListNode fast=head,slow=head,pre=null;
            while(fast!=null && fast.next!=null){
                fast = fast.next.next;
                pre = slow;
                slow = slow.next;
            }
            // head --->pre--->slow--->fast
            pre.next = null;
            // 分治前半部分 head ---> pre
            ListNode l1 = sortList(head);
            // 分治后半部分 slow ---> fast
            ListNode l2 = sortList(slow);
            // 将两个有序链表 l1,l2 归并
            return merge(l1,l2);
        }
    
        public ListNode merge(ListNode l1,ListNode l2){
            ListNode head = null,p = null;
            while(l1!=null && l2 != null){
                ListNode node;
                if(l1.val<l2.val){
                    node=l1;
                    l1=l1.next;
                }else{
                    node = l2;
                    l2 = l2.next;
                }
                if(p == null){
                    head = node;
                }else{
                    p.next = node;
                }
                p=node;
            }
            if(l1 != null){
                p.next = l1;
            }
            if(l2 != null){
                p.next = l2;
            }
            return head;
        }
    }
    
  • 相关阅读:
    bug排查
    做接口测试没反应
    wcf配置文件
    mvc学习-编辑提交需要注意-mvc重点
    大批量导出思路
    进程基础知识
    (转)JMS事务
    (转)JMS简明学习教程
    (转)Linux下使用system()函数一定要谨慎
    LInux文件基础知识和文件目录操作(二)文件I/O操作
  • 原文地址:https://www.cnblogs.com/lippon/p/14117715.html
Copyright © 2020-2023  润新知