归并排序
简介
通过找到中间值,然后递归分别从左区间和右区间找中间值,最终将所给的值划分为单个块,然后进行一步一步回溯,分块由两个单个分区排序后合成一个,以此类推,最后实现有序排序
时间复杂度
最优 nlogn
最差 nlogn
空间复杂度
O(n)
优点
归并排序是一种稳定的排序算法,且适用于各种数据情况。它的主要优点是具有稳定的时间复杂度和良好的性能。尤其是在对链表等非随机访问的数据结构进行排序时,归并排序是一种常用的选择。
解题模版
public void mergeSort(int[] nums) {
if (nums == null || nums.length <= 1) {
return;
}
mergeSort(nums, 0, nums.length - 1);
}
private void mergeSort(int[] nums, int left, int right) {
if (left >= right) {
return;
}
int mid = left + (right - left) / 2;
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
merge(nums, left, mid, right);
}
private void merge(int[] nums, int left, int mid, int right) {
int[] temp = new int[right - left + 1];
int i = left, j = mid + 1, k = 0;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
}
}
while (i <= mid) {
temp[k++] = nums[i++];
}
while (j <= right) {
temp[k++] = nums[j++];
}
System.arraycopy(temp, 0, nums, left, temp.length);
}
练习题
88. 合并两个有序数组
模版的后半部分,使用三个指针分别指向nums1,nums2,nums1的尾部,从而进行比较赋值,换位
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int p1 = m-1;
int p2 = n-1;
int p = m+n-1;
while(p1>=0 && p2 >= 0){
if(nums1[p1] >nums2[p2]){
nums1[p] = nums1[p1];
p1--;
}else{
nums1[p] = nums2[p2];
p2--;
}
p--;
}
while(p2>=0){
nums1[p] = nums2[p2];
p2--;
p--;
}
}
}
- 排序链表
同样的思路放在链表中,通过找到中间值,然后将其中间值下一个指向空值,将链表分成两个,以此类推,分成n份,之后在重新连接,最终形成一个新的排序好的链表
class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode mid = findMiddle(head);
ListNode midNext = mid.next;
mid.next = null;
ListNode left = sortList(head);
ListNode right = sortList(midNext);
return merge(left,right);
}
private ListNode findMiddle(ListNode head){
ListNode slow = head;
ListNode fast = head.next;
while(fast!= null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
private ListNode merge(ListNode l1,ListNode l2){
ListNode dummy = new ListNode(-1);
ListNode curr = dummy;
while(l1 != null && l2 != null){
if(l1.val <l2.val){
curr.next = l1;
l1 = l1.next;
}else{
curr.next = l2;
l2 = l2.next;
}
curr = curr.next;
}
if(l1 != null){
curr.next = l1;
}
if(l2 != null){
curr.next = l2;
}
return dummy.next;
}
}
颜色分类
这个题可以i当做所有排序算法的练习题,使用归并排序,直接套用模版即可
public void sortColors(int []nums){
if(nums == null || nums.length <=1){
return;
}
mergeSort(nums,0,nums.length-1);
}
public void mergeSort(int [] nums,int left,int right){
if(left>=right){
return;
}
int mid = left+(right-left)/2;
mergeSort(nums,left,mid);
mergeSort(nums,mid+1,right);
merge(nums,left,mid,right);
}
private void merge(int []nums,int left,int mid ,int right){
int []temp = new int[right-left+1];
int i = left,j = mid+1,k=0;
while(i<=mid && j<= right){
if(nums[i]<=nums[j]){
temp[k++] = nums[i++];
}else{
temp[k++] = nums[j++];
}
}
while(i<=mid){
temp[k++] = nums[i++];
}
while(j<= right){
temp[k++] = nums[j++];
}
System.arraycopy(temp,0,nums,left,temp.length);
}
}