归并排序是利用递归与分治技术将数据序列划分为越来越小的半子表,再对半子表排序,最后再用递归方法将排好序的半子表合并成越来越大的有序列表。
归并排序算法的原理如下:对于给定的一组记录(假设共有n个记录),首先将每两个相邻的长度为1的子序列进行排序,得到n/2(向上取整)个长度为2或1的有序子序列,再将其两两归并,反复执行从过程,直到得到一个有序序列。所以,归并排序的关键就是两步:(1)划分半子表;(2)合并半子表。以数组{49,38,65,97,76,13,27}为例,归并排序的具体步骤如下:
Java代码实现
import java.util.Arrays;
public class MergeSort_Algorithm {
public static void main(String args[]){
int[] arr = {49,38,65,97,76,13,27};
sort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
public static void sort(int[] arr, int L, int R) {
if(L == R) {
return;
}
int mid = L + ((R - L) >> 1);
sort(arr, L, mid);
sort(arr, mid + 1, R);
merge(arr, L, mid, R);
}
public static void merge(int[] arr, int L, int mid, int R) {
int[] temp = new int[R - L + 1];
int i = 0;
int p1 = L;
int p2 = mid + 1;
// 比较左右两部分的元素,哪个小,把那个元素填入temp中
while(p1 <= mid && p2 <= R) {
temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
// 上面的循环退出后,把剩余的元素依次填入到temp中
// 以下两个while只有一个会执行
while(p1 <= mid) {
temp[i++] = arr[p1++];
}
while(p2 <= R) {
temp[i++] = arr[p2++];
}
// 把最终的排序的结果复制给原数组
for(i = 0; i < temp.length; i++) {
arr[L + i] = temp[i];
}
}
}
运行结果
以上是数组的归并排序,数组存储的归并排序 时间复杂度O(nlogn)空间复杂度 O(n)
以下是链表的归并排序,链表存储的归并排序 时间复杂度O(nlogn)空间复杂度 O(1)
Java代码实现:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
/*数组存储的归并排序 时间复杂度O(nlogn)空间复杂度 O(n)
链表存储的归并排序 时间复杂度O(nlogn)空间复杂度 O(1)*/
public class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null)
return head;
//快慢指针查找链表中间节点
ListNode slow = head;
ListNode fast = head;
while(fast.next != null && fast.next.next != null){
slow = slow.next;
fast = fast.next.next;
}
ListNode midNext = slow.next;
slow.next = null;
return merge(sortList(head),sortList(midNext));
}
private ListNode merge(ListNode head1,ListNode head2){
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
while(head1!=null && head2!=null){
if(head1.val <= head2.val){
cur.next=head1;
head1=head1.next;
}else{
cur.next=head2;
head2=head2.next;
}
cur=cur.next;
}
if(head1!=null){
cur.next=head1;
}else if(head2!=null){
cur.next=head2;
}
return dummy.next;
}
}