算法——排序链表

给定一个乱序的链表,要求将链表进行排序后然后返回头结点,要求时间复杂度为 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;
    }
}
原文地址:https://www.cnblogs.com/lippon/p/14117715.html