归并排序
传统的归并排序
给定一个数组,将数组排序
思路:将数组从中间分为两部分,分别对两个子数组进行排序,完成排序后将两个子数租整合,至此整个数组排序完成
leetcode 912将数组排序
public class MergeSort {
public void mergeSort (int[] nums) {
process(nums, 0, nums.length-1);
}
public void process (int[] nums, int L, int R) {
if (L == R) return;
int mid = L + ((R-L) >> 1);
process(nums, L, mid);
process(nums, mid+1, R);
merge(nums, L, mid, R);
}
public void merge(int[] nums, int L, int M, int R) {
int[] help = new int[R-L+1];
int p1 = L, p2 = M+1, i=0;
while (p1 <= M && p2 <= R) {
help[i++] = nums[p1] < nums[p2] ? nums[p1++] : nums[p2++];
}
while (p1 <= M) {
help[i++] = nums[p1++];
}
while (p2 <= R) {
help[i++] = nums[p2++];
}
for (int k = 0; k < help.length; k++) {
nums[L+k] = help[k];
}
}
}
链表的归并排序
给一个链表的头结点,将链表完成排序 leetcode 148
链表的归并排序与数组的不同之处在于
- 寻找中间结点时需要使用快慢指针
- 不需要定义辅助数组,只需要新建一个头结点(头结点不存放任何数据,只是逻辑上的头结点)将排序好的链表串联起来,返回头结点的下一个结点就是链表真实头结点
public class ListMergeSort {
public ListNode listMergeSort(ListNode head) {
if (head == null || head.next == null) return head;
// 定义快慢指针,找到链表中点位置 单数情况下中点 偶数情况下中线左侧位置
ListNode fast = head, slow = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
// 记录中点右侧结点
ListNode right = slow.next;
slow.next = null;
ListNode l1 = listMergeSort(head);
ListNode l2 = listMergeSort(right);
mergeTwoList(l1, l2);
}
public void mergeTwoList(ListNode L, listNode R) {
ListNode head = new ListNode();
ListNode tail = head;
ListNode p1 = L, p2 = R;
while (p1 != null && p2 != null) {
if (p1.val <= p2.val) {
tail.next = p1;
tail = tail.next;
p1 = p1.next;
}else {
tail.next = p2;
tail = tail.next;
p2 = p2.next;
}
}
if (p1) tail.next = p1;
if (p2) tail.next = p2;
return head.next;
}
}