(恋上数据结构笔记):归并排序(Merge Sort)

目录

归并排序

序列分割-divide

序列合并-merge

原地合并-merge

左边先结束

右边先结束

代码实现复杂度分析

归并排序

  • 1945年由约翰·冯·诺伊曼(John von Neumann)首次提出。
  • 执行流程
    • ① 不断地将当前序列平均分割成 2 个子序列
      • 直到不能再分割(序列中只剩 1 个元素)
    • ② 不断地将 2 个子序列合并成一个有序序列
      • 直到最终只剩下 1 个有序序列

序列分割-divide

protected void sort() {
	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); // 合并整个序列
}

序列合并-merge

原地合并-merge

  • 将两个序列合并时,不一定要合并到新空间,可以合理的利用原空间实现原地合并。
  • 例如:
    • 将 array的左半部分[begin, mid),备份到 leftArray 中;
    • 然后将 leftArray 视为左子序列,arrary的右半部分[mid, end] 视为右子序列;
    • 将左子序列和右子序列合并到 array 中。

  • 合并过程

  • 更容易理解的示意图(总体四个元素为例):

左边先结束

右边先结束

代码实现

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
		}
	}
}
}
  • 测试

复杂度分析

【常见的递推式和复杂度】

已标记关键词 清除标记
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页