【算法】【排序算法】【03】归并排序

在这里插入图片描述

归并排序

归并排序的核心思想:
将无序数组分成两份,分别对左边和右边排序;
将排好序的左边和排好序的右边合并在一起;
在这里插入图片描述

public class _08_Merge1 {
    public static void mergeSort(int[] arr) {

        mergeSort(arr, 0, arr.length - 1);
    }

    private static void mergeSort(int[] arr, int low, int high) {
        if (low == high) return;
        int mid = (low + high) >> 1;
        //2. sort left
        mergeSort(arr, low, mid);
        //3. sort right
        mergeSort(arr, mid + 1, high);
        //4. merge
        merge(arr, low, mid, high);
    }

    private static int[] copyList(int[] arr, int start, int end) {
        int[] result = new int[end - start + 1];
        for (int i = start; i <= end; i++) {
            result[i - start] = arr[i];
        }
        return result;
    }


    private static void merge(int[] arr, int low, int mid, int high) {
        int left = 0;
        int right = 0;

        int[] leftArr = copyList(arr, low, mid);
        int leftLen = leftArr.length;
        int[] rightArr = copyList(arr, mid + 1, high);
        int rightLen = rightArr.length;

        for (int i = low; i <= high; i++) {
            if (left >= leftLen || right < rightLen && leftArr[left] >= rightArr[right]) {
                arr[i] = rightArr[right];
                right++;
            } else {
                //else if(right > high || left <= mid && arr[left] <= arr[right] )
                arr[i] = leftArr[left];
                left++;
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {26, 15, 23, 48, 54, 2, 35, 9, 20, 36, 71, 32, 37, 65};

        mergeSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}
【_08_MergeSort】
稳定性:true 	耗时:0.006s(6ms) 	比较:26.09万	 交换:0
------------------------------------------------------------------
【_03_HeapSort】
稳定性:false 	耗时:0.012s(12ms) 	比较:51.05万	 交换:2.00------------------------------------------------------------------
【_05_Insert_BinarySearch】
稳定性:true 	耗时:0.261s(261ms) 	比较:26.07万	 交换:0
------------------------------------------------------------------
【_02_Select】
稳定性:true 	耗时:0.393s(393ms) 	比较:2.00亿	 交换:2.00------------------------------------------------------------------
【_04_Insert】
稳定性:true 	耗时:0.421s(421ms) 	比较:1.01亿	 交换:1.01亿
------------------------------------------------------------------
【_04_Insert2】
稳定性:true 	耗时:0.555s(555ms) 	比较:1.34亿	 交换:0
------------------------------------------------------------------
【_01_Bubble】
稳定性:true 	耗时:1.287s(1287ms) 	比较:2.00亿	 交换:1.01亿
------------------------------------------------------------------
【_01_Bubble_3】
稳定性:true 	耗时:1.827s(1827ms) 	比较:2.00亿	 交换:1.01亿
------------------------------------------------------------------
【_01_Bubble_2】
稳定性:true 	耗时:1.875s(1875ms) 	比较:2.00亿	 交换:1.01亿
------------------------------------------------------------------

复杂度分析

T(n) = 2 ∗ T(n/2) + O(n)
T(1) = 1

最好、最坏时间复杂度都 O(nlogn)

常见的递推式与复杂度

在这里插入图片描述

merge优化

在这里插入图片描述
只将左边备份出来,这样节省了空间;
从左往右添加到arr中,如果左边数组遍历结束了,说明左边的插完了

/**
 * 归并排序
 */
@SuppressWarnings("unchecked")
	public class MergeSort <T extends Comparable<T>> extends Sort<T> {
	private T[] leftArray;
	
	@Override
	protected void sort() {
		// 准备一段临时的数组空间, 在merge操作中使用
		leftArray = (T[])new Comparable[array.length >> 1];
		sort(0, array.length);
	}
	
	/**
	 * 对 [begin, end) 范围的数据进行归并排序
	 */	
	private void sort(int begin, int end){
		if(end - begin < 2) return; // 至少要2个元素
		
		int mid = (begin + end) >> 1;
		sort(begin, mid); // 归并排序左半子序列
		sort(mid, end);	// 归并排序右半子序列
		merge(begin, mid, end); // 合并整个序列
	}
	
	/**
	 * 将 [begin, mid) 和 [mid, end) 范围的序列合并成一个有序序列
	 */
	private void merge(int begin, int mid, int end){
		int li = 0, le = mid - begin; // 左边数组(基于leftArray)
		int ri = mid, re = end;	// 右边数组(array)
		int ai = begin; // array的索引
		
		// 备份左边数组到leftArray
		for(int i = li; i < le; i++){
			leftArray[i] = array[begin + i];
		}
		
		// 如果左边还没有结束
		while(li < le){ // li == le 左边结束, 则直接结束归并
			if(ri < re && cmp(array[ri], leftArray[li]) < 0){ // cmp改为<=0会失去稳定性
				array[ai++] = array[ri++]; // 右边<左边, 拷贝右边数组到array
			}else{
				array[ai++] = leftArray[li++]; // 左边<=右边, 拷贝左边数组到array
			}
		}
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值