链表的归并排序
就是排序找中点,然后中点位置后一个为null,切断链表,也就是分而治之每次分割一半,一直往后分割,直到只剩下一个节点,或者没有节点停止。
public class ListNode{
int val;
ListNode next;
public ListNode(int x){
this.val = x;
}
}
public ListNode sortList(ListNode head) {
// 链表排序
// 时间复杂度O(nlogn),常数空间复杂度,不能用任何的额外空间
// 这使用的是归并排序
// 2-1-4-3 | 1 2 3 4
if(head == null || head.next == null) return head;
ListNode fast = head;
ListNode slow = head;
while(fast.next!=null && fast.next.next != null){
slow = slow.next;
fast = fast.next.next;
}
// 获得slow
ListNode right = sortList(slow.next);
// 一定要先slow.next = null,否则head找中点会越界
slow.next = null;
// 此时被截断成一半
ListNode left = sortList(head);
return mergeList(left, right);
}
public ListNode mergeList(ListNode left, ListNode right){
ListNode dummyNode = new ListNode(0);
ListNode cur = dummyNode;
while(left != null && right != null){
if(left.val < right.val){
cur.next = left;
left = left.next;
}else{
cur.next = right;
right = right.next;
}
cur = cur.next;
}
cur.next = left == null ? right : left;
return dummyNode.next;
}
链表数组归并排序
可能会含有多个数组,对其归并排序,也是采用找寻终点,但是需要注意,此时找寻的终点,只是数组中的一部分,但是他们都是有结尾null的,所以可以根据index来寻找,跟真实数组的归并排序实质是差不多的,主要是在归并的时候,有使用到递归的操作。
public ListNode mergeKLists(ListNode[] lists) {
// 使用归并排序
if (lists == null || lists.length == 0) return lists[0];
return merge(lists, 0, lists.length - 1);
}
public ListNode merge(ListNode[] list, int left, int right){
// 如果相等,终止条件
if(left == right) return list[left];
// 找中点
int m = left + (right - left)/2;
ListNode l1 = merge(list,left,m);
ListNode l2 = merge(list,m+1,right);
return mergeListNode(l1,l2);
}
public static ListNode mergeListNode(ListNode l1, ListNode l2){
// 递归方式:这里的递归十分精妙!
if(l1 == null) return l2;
if(l2 == null) return l1;
if(l1.val < l2.val){
l1.next = mergeListNode(l1.next,l2);
return l1;
}else{
l2.next = mergeListNode(l2.next,l1);
return l2;
}
}
递归方式很重要,在二叉树的学习中要更加注意递归方法的学习!加油!